2010-12-07 3 views
34

Я хотел бы реализовать метод, который отображает диалог, ждет, пока диалог не будет отклонен, а затем вернет результат в зависимости от содержимого диалогового окна. Это возможно?Android: подождите от ввода пользователем диалогового окна?

public String getUserInput() 
{ 
    //do something to show dialog 
    String input = //get input from dialog 
    return input; 
} 

Я на самом деле пытаюсь реализовать интерфейс, который имеет метод «общественный Строка getUserInput()», где возвращаемая строка должна быть восстановлена ​​с помощью диалога. Это легко сделать в java, кажется невозможным в android?

EDIT: Проводка некоторые примеры кода в соответствии с просьбой в комментарии

getInput() должна быть вызвана из фонового потока (я называю это из AsynchTask). getInput() отображает диалог и вызывает ожидание. Когда в диалоговом окне нажата кнопка ok, диалог устанавливает пользовательский ввод в переменной-члене и вызывает уведомление. Когда вызывается уведомление, getInput() продолжается и возвращает переменную-член.

String m_Input; 

public synchronized String getInput() 
{ 
    runOnUiThread(new Runnable() 
    { 
     @Override 
     public void run() 
     { 
      AlertDialog.Builder alert = new AlertDialog.Builder(context); 
      //customize alert dialog to allow desired input 
      alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() { 
      public void onClick(DialogInterface dialog, int whichButton) 
      { 
          m_Input = alert.getCustomInput(); 
          notify(); 
      } 
     }); 
     alert.show(); 
     } 
    }); 

    try 
    { 
     wait(); 
    } 
    catch (InterruptedException e) 
    { 
    } 

    return m_Input; 
} 
+5

Вы не можете дождаться пользователя в методе, вызываемом в потоке пользовательского интерфейса. Таким образом, вы должны либо переключиться на управляемую событиями модель потока программ, либо вызвать это из фонового потока, который может подождать, пока метод onWhatever() не будет вызван в поток пользовательского интерфейса в ответ на обновления действий пользователя, которые ожидал ваш фоновый метод. – 2010-12-07 20:42:50

+0

Я действительно не понимаю, не могли бы вы объяснить, как я назвал бы это из фонового потока, а затем верну свою строку вверх на WhatWhatever()? – ab11 2010-12-07 20:46:52

+0

Потому что, если вы будете блокировать поток пользовательского интерфейса более чем на 3 (?), Я думаю, что было три секунды, когда вы получите всплывающее диалоговое окно ANR, спрашивающее, хотите ли вы закрыть приложение. Никогда не запускайте блокирующие элементы в потоке пользовательского интерфейса в Android. – 2010-12-07 20:56:24

ответ

11

Спасибо за все отзывы, я смог решить это, используя фоновый поток вместе с wait() и уведомить (). Я признаю, что это не самая лучшая идея для данной парадигмы, но нужно было соответствовать библиотеке, с которой я работаю.

1

Что-то, как это будет делать

/** 
* 
*/ 

import android.app.Activity; 
import android.content.Intent; 
import android.os.Bundle; 
import android.view.View; 
import android.view.WindowManager; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.EditText; 

/** 
* @author 
*/ 
public class TextEntryActivity extends Activity { 
    private EditText et; 

    /* 
    * (non-Javadoc) 
    * @see android.app.Activity#onCreate(android.os.Bundle) 
    */ 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setContentView(R.layout.activity_text_entry); 
     getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, 
       WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 
     // title 
     try { 
      String s = getIntent().getExtras().getString("title"); 
      if (s.length() > 0) { 
       this.setTitle(s); 
      } 
     } catch (Exception e) { 
     } 
     // value 

     try { 
      et = ((EditText) findViewById(R.id.txtValue)); 
      et.setText(getIntent().getExtras().getString("value")); 
     } catch (Exception e) { 
     } 
     // button 
     ((Button) findViewById(R.id.btnDone)).setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       executeDone(); 
      } 
     }); 
    } 

    /* (non-Javadoc) 
    * @see android.app.Activity#onBackPressed() 
    */ 
    @Override 
    public void onBackPressed() { 
     executeDone(); 
     super.onBackPressed(); 
    } 

    /** 
    * 
    */ 
    private void executeDone() { 
     Intent resultIntent = new Intent(); 
     resultIntent.putExtra("value", TextEntryActivity.this.et.getText().toString()); 
     setResult(Activity.RESULT_OK, resultIntent); 
     finish(); 
    } 


} 

Запуск ракеты:

public void launchPreferedNameEdit() { 
    Intent foo = new Intent(this, TextEntryActivity.class); 
    foo.putExtra("value", objItem.getPreferedNickname()); 
    this.startActivityForResult(foo, EDIT_PREFERED_NAME); 
} 

Вы получаете результат, используя

protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    switch (requestCode) { 
     case EDIT_PREFERED_NAME: 
      try { 
       String value = data.getStringExtra("value"); 
       if (value != null && value.length() > 0) { 

       } 
      } catch (Exception e) { 
      } 
      break; 
     default: 
      break; 
    } 
} 
27

Возможно ли это?

Нет. В Android нет блокирующего пользовательского интерфейса. Все асинхронно.

UPDATE

В ответ на некоторые из ваших комментариев на сам вопрос, вы не можете отобразить пользовательский интерфейс от фонового потока. Как я писал в этом ответе, в Android нет блокирующей модели пользовательского интерфейса. Просто поместите свой код в обработчик кнопки для своего диалога, который вы хотите выполнить, когда диалог будет принят, например, в this sample project.

10

Правильный способ сделать это - программа, управляемая событиями, то есть «не позвоните нам, мы вам позвоним».

В простом программировании в режиме консоли ваш код имеет тенденцию вызывать блокировку входных функций, которые не возвращаются до тех пор, пока вы не получите значение.

Многие среды программирования gui работают по-другому - ваш код обычно не работает, но вместо этого он вызывается операционной системой/оконным менеджером, когда возникает что-то потенциальное интерес. Вы делаете что-то в ответ на это и сразу возвращаетесь - если вы этого не сделаете, вы не можете быть уведомлены о чем-либо еще, так как у ОС нет возможности связаться с вами до вашего возвращения. (По сравнению с win32, это похоже на то, что цикл сообщений реализован Android, и вы можете записать остальную часть кода, который цикл сообщений вызывает с событиями - если вы не вернетесь незамедлительно, зависает контур сообщения)

В результате вам необходимо переосмыслить концепцию потока программ. Вместо того, чтобы записывать список дел в виде простой серии утверждений, подумайте об этом как о последовательности действий, которые зависят друг от друга и от ввода. Помните, какое действие вы сейчас используете в переменной состояния.Когда вы вызываетесь с событием, таким как ввод пользователя, посмотрите, означает ли это событие, что теперь можно перейти к следующему шагу, и если это так обновить переменную состояния перед оперативным возвратом в ОС, чтобы иметь возможность получить следующую мероприятие. Если событие было не тем, что вам было нужно, просто возвращайтесь без обновления вашего состояния.

Если эта модель не работает для вас, то вы можете написать фоновый поток программной логики, который работает как приложение в режиме консоли, используя блокирующий вход. Но ваши функции ввода будут просто ждать флага или что-то, что будет уведомлено о том, что вход доступен. Затем в потоке пользовательского интерфейса, где Android отправляет события, вы обновляете флаг и сразу возвращаетесь. Фоновый поток видит, что флаг изменился, указав, что данные были предоставлены, и продолжает выполнение. (Что-то вроде эмулятора терминала android делает это до крайности, где фоновым компонентом на самом деле является другой процесс - консольный режим linux one, и он получает свои данные, используя потенциально блокирующий ввод-вывод из труб. Компонент java принимает события пользовательского интерфейса Android и заполняет символы в трубе stdin и вытаскивает их из канала stdout для отображения на экране.)

0

CASE: Мои данные были готовы к процессам после события прослушивания изменения предпочтений, и мне нужно было добавить строку запроса от пользователя. Невозможно открыть диалог оповещений, когда меню опций открыто ... поэтому мне пришлось подождать. Я бросил наполовину полный объект в следующую активность в рабочем процессе и установил onResume(), чтобы проверить, был ли его заполнитель! Null, и в этом случае я вытащил диалог и закончил объект * «в обработчике кнопки диалога "*.

Поскольку это мой первый пост, я не могу проголосовать за правильный ответ, указанный выше, но хочу, чтобы кто-то еще использовал это время и элегантность менее правильных решений. Диалог - это место.

0

Вы можете думать в терминах конечного автомата, где, если вы изначально требуете ввода пользователя в первый раз, вы можете установить флаг для отметки «пользовательский ввод необходим» или что-то еще. Затем после обработки события вы проверяете этот флаг, и если он установлен, вы запускаете диалог как единственное действие для события и устанавливаете флаг. Затем из обработчика события диалога после обработки ввода пользователя вы можете вызвать код, обычно предназначенный для случая, когда диалог не нужен.

0

Мне было трудно понять все предлагаемые выше решения, поэтому я нашел свой собственный.

Я обернуть код Thats она должна выполнять после ввода пользователя OK'ed в работоспособном, например, так:

Runnable rOpenFile = new Runnable() { 
     @Override 
     public void run() { 
      .... code to perform 
     } 
    } 

Тогда прямо ниже, я прохожу имя работоспособных функций для пользователя диалогового метода.

userInput("Open File", rOpenFile); 

Метод UserInput основан на построителе alertDialog, как описано выше. Когда пользовательский ввод Ok'ed, он запускает предполагаемый запуск.

private void userInput(String sTitle, final Runnable func) { 
    AlertDialog.Builder aBuilder = new AlertDialog.Builder(this); 

    aBuilder.setTitle(sTitle); 
    final EditText input = new EditText(this); 
    input.setInputType(InputType.TYPE_CLASS_TEXT); 
    aBuilder.setView(input); 

    bDialogDone = false; 

    aBuilder.setPositiveButton("Ok", new DialogInterface.OnClickListener() { 
     @Override 
     public void onClick(DialogInterface dialog, int which) { 
      final String sText = input.getText().toString(); 
      sEingabe = sText; 
      func.run(); 
     } 
    }); 
    aBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { 
     @Override 
     public void onClick(DialogInterface dialog, int which) { 
      dialog.cancel(); 
      sEingabe = ""; 
     } 
    }); 

    aBuilder.show(); 
} 
Смежные вопросы