Android:等待来自对话框的用户输入?

时间:2010-12-07 20:33:55

标签: android modal-dialog

我想实现一个显示对话框的方法,等待对话框解除,然后根据对话框内容返回结果。这可能吗?

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

我实际上是在尝试实现一个具有“public String getUserInput()”方法的接口,其中必须通过对话框检索返回的String。这很容易在java中完成,在android中似乎不可能吗?

编辑:根据评论中的要求发布一些示例代码

必须从后台线程调用

getInput()(我从AsynchTask中调用它)。 getInput()显示一个对话框并调用wait。在对话框上按下确定按钮时,对话框在成员变量中设置用户输入并调用notify。调用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;
}

8 个答案:

答案 0 :(得分:29)

  

这可能吗?

没有。 Android中没有阻止UI模型。一切都是异步的。

<强>更新

在回答您对问题本身的一些评论时,您无法从后台线程显示UI。正如我在这个答案中所写,Android中没有阻止UI模型。只需将代码放在对话框的按钮处理程序中,然后在接受对话框时执行该对话框,例如在this sample project中。

答案 1 :(得分:11)

感谢所有的反馈,我能够使用后台线程以及wait()和notify()来解决这个问题。我认识到这不是给定范式的最佳想法,但有必要符合我正在使用的图书馆。

答案 2 :(得分:10)

这样做的正确方法是一个事件驱动的程序模型,即“不要打电话给我们,我们会打电话给你”。

在简单的控制台模式编程中,您的代码倾向于调用阻塞输入函数,这些函数在您获得值之前不会返回。

许多gui编程环境的工作方式不同 - 您的代码通常不会运行,而是在发生可能感兴趣的事情时由操作系统/窗口管理器调用。你做了一些事情以回应这个并立即返回 - 如果你不这样做,你不能得到任何其他通知,因为操作系统在你返回之前无法与你联系。 (与win32相比,就好像消息循环由Android实现,你只能编写消息循环使用事件调用的其余代码 - 如果你没有及时返回,消息循环会挂起)< / p>

因此,您需要重新考虑您的程序流概念。不要将待办事项列表写为一系列简单的陈述,而应将其视为一系列依赖于彼此和输入的动作。记住您在状态变量中当前正在执行的操作。当您使用用户输入等事件调用时,查看该事件是否意味着现在可以继续执行下一步,如果是,则更新状态变量,然后立即返回操作系统以便能够接收下一个事件。如果事件不是您所需要的,那么只需返回而不更新您的州。

如果这个模型不适合你,你可以做的是编写程序逻辑的后台线程,它使用阻塞输入像控制台模式应用程序一样运行。但是你的输入函数实际上只是等待一个标志或某些东西被通知输入可用。然后在Android传递事件的UI线程上,更新标志并立即返回。后台线程看到标志已更改以指示已提供数据,并继续执行。 (像Android终端模拟器这样的东西把它带到了一个极端,其中后台组件实际上是另一个进程 - 一个控制台模式linux,它使用可能阻塞来自管道的I / O来获取它的输入.java组件接受android UI事件和将字符填充到stdin管道中并将它们从stdout管道中拉出以显示在屏幕上。)

答案 3 :(得分:4)

到目前为止,我很难理解上面提供的所有解决方案,所以我找到了自己的解决方案。

我在可运行的用户输入正常后包装应该执行的代码,如下所示:

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

然后就在下面,我将runnable函数的名称传递给用户对话框方法。

    userInput("Open File", rOpenFile);

userInput方法基于alertDialog构建器,如上所述。当用户输入“Ok”时,它将启动预期的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();
}

答案 4 :(得分: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;
    }
}

答案 5 :(得分:0)

CASE:我的数据已准备好在首选项更改侦听器事件之后成为进程,我需要添加从用户查询的String。当选项菜单打开时,似乎无法弹出警告对话框......所以我不得不等待。我将半完成对象放入工作流中的下一个活动,并设置其onResume()以检查其占位符是否为null。在这种情况下,我弹出对话框并完成按钮中的对象 *“对话框的处理程序“*

由于这是我的第一篇文章,我不能投票给出上面给出的正确答案,但是想要挽救其他任何人在这个时间和优雅的不太正确的解决方案。对话就是这个地方。

答案 6 :(得分:0)

您可以根据状态机来考虑如果您最初需要首次用户输入,则可以设置标记以标记&#34;所需的用户输入&#34;管他呢。然后在处理事件时检查该标志,如果设置,则启动对话框作为事件的唯一操作并取消设置标志。然后在处理用户输入后从对话框事件处理程序中调用通常用于不需要对话框时的代码。

答案 7 :(得分:0)

供我参考,我刚刚做了一个对话框。

它将显示并等待,然后关闭

然后我部署Java等待并通知它,该函数可以复制并直接运行。

private final Object lock = new Lock();
private static final class Lock {}
private void showWaitDialog(final String message, final int time_to_wait) { //ms
    if(this.isFinishing()) return;
    final String TTAG = "[showWaitDialog]";
    Log.d(TTAG, "dialog going to show");
    final ProgressDialog waitProgress = ProgressDialog.show(this, "WARNING", message, true);
    waitProgress.setCancelable(false);
    waitProgress.setOnShowListener(new DialogInterface.OnShowListener() { //callback got the asynchronous
        @Override
        public void onShow(DialogInterface dialog) {
            Log.d(TTAG, "dialog showed");
            synchronized (lock) {
                try {
                    Log.d(TTAG, "main thread going to wait");
                    lock.wait();
                } catch (InterruptedException e) {
                    Log.e(TTAG, e.toString());
                    Log.e(TTAG, "main thread going ahead");
                }
            }
        }
    });
    new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (lock) {
                try {
                    Thread.sleep(time_to_wait);
                } catch (Exception e) {
                    Log.d(TTAG, e.toString());
                }
                lock.notifyAll();
                Log.d(TTAG, "dialog notified");
                waitProgress.dismiss();
            }
        }
    }).start();
}
相关问题