Android: ждать ввода пользователя из диалога? - PullRequest
37 голосов
/ 07 декабря 2010

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

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

Я на самом деле пытаюсь реализовать интерфейс, который имеет метод "public String getUserInput ()", где возвращаемая строка должна быть получена через диалог.Это легко сделать в Java, кажется невозможным в Android?

РЕДАКТИРОВАТЬ: Публикация некоторого примера кода, как требуется в комментарии

getInput() должна вызываться из фонового потока (я вызываю его изAsynchTask).getInput () отображает диалог и вызывает ожидание.Когда в диалоговом окне нажимается кнопка «ОК», диалоговое окно устанавливает пользовательский ввод в переменную-член и вызывает уведомление.Когда вызывается notify, 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;
}

Ответы [ 7 ]

30 голосов
/ 07 декабря 2010

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

Нет. В Android нет модели блокировки интерфейса. Все асинхронно.

UPDATE

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

11 голосов
/ 08 декабря 2010

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

10 голосов
/ 08 декабря 2010

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

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

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

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

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

4 голосов
/ 13 января 2018

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

Я обертываю код, который должен выполняться после того, как пользовательский ввод в порядке, в исполняемом файле,вот так:

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

Затем прямо под этим я передаю имя запускаемой функции методу пользовательского диалога.

    userInput("Open File", rOpenFile);

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

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();
}
1 голос
/ 07 декабря 2010

Нечто подобное может сделать

/**
 *
 */

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;
    }
}
0 голосов
/ 29 мая 2014

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

0 голосов
/ 27 июня 2011

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

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

...