【问题标题】:How to update UI via Handler如何通过 Handler 更新 UI
【发布时间】:2010-11-09 15:41:56
【问题描述】:

所以,我收到一个错误,我从错误的线程更新 UI。这当然不是我的本意。我的案例很长,但我会尽量用代码 sn-ps 来做到这一点。我的最终目标是在一个单独的线程中运行一项昂贵的任务,并将沿途发生的更新发布到我的 listView 的末尾。

public class test extends Activity {

   private ArrayAdapter<String> _mOutArrayAdapter;
   private ListView _mOutView;
   private EditText _mCmdEditText;
   private Button _mRunButton;
   private Interpreter _interpreter;

   // Need handler for callbacks to the UI thread
   public final Handler _mHandler = new Handler() {
    public void handleMessage(Message msg) {
        _mOutArrayAdapter.add(msg.getData().getString("text"));
    };
   };

   // Create runnable for posting
   final Runnable mUpdateResults = new Runnable() {
       public void run() {
           updateResultsInUi();
       }
   };

   /** Called when the activity is first created. */
    @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);

       _interpreter = new Interpreter(true);

       _mOutView = (ListView)findViewById(R.id.out);
       _mCmdEditText = (EditText)findViewById(R.id.edit_command);
       _mRunButton = (Button)findViewById(R.id.button_run);

       _mOutArrayAdapter = new ArrayAdapter<String>(this, R.layout.message);
       _mOutView.setAdapter(_mOutArrayAdapter);
       _mOutArrayAdapter.clear();
       _interpreter.setOutputAdapter(_mOutArrayAdapter);

       Thread t = new Thread() {
            public void run() {
               _mResults = _interpreter.executeExpression("startup;",_mHandler);
               _mHandler.post(mUpdateResults);
           }
       };
       t.start();

   ); 

然后在解释器中我这样做:

public class Interpreter 
{

    private static Handler _mHandler;

    public String executeExpression(String expression, Handler handler)
    {  
        _mHandler = handler;

        //Do a bunch of stuff that sometimes calls displayText from this class or from others

        return answer;
    }

    public void displayText(String text)
    {
        Message msg = new Message();
        Bundle bndl = new Bundle();
        bndl.putString("text", text);
        msg.setData(bndl);
        _mHandler.dispatchMessage(msg);
    }
}

最终答案的显示有效。并且 dispatchMessage 最终触发了 handleMessage,但它抛出了一个错误,我无法从 UI 线程之外修改 UI,我知道这是非法的。那么,我做错了什么?

谢谢!

【问题讨论】:

  • 尝试使用异步任务,正如其他人所说,不确定您的代码在做什么
  • 你是对的,sendMessage是用来发送handler的handleMessage中接收到的消息。

标签: android multithreading


【解决方案1】:
_mHandler.dispatchMessage(msg);

dispatchMessage() 导致 Handler 在当前线程上运行。 http://developer.android.com/reference/android/os/Handler.html

dispatchMessage(消息消息)

在此处处理系统消息。

您应该使用_mHandler.sendMessage(msg); 它将消息放入队列中,由声明处理程序的线程运行。

sendMessage(消息消息)

在当前时间之前的所有未决消息之后,将消息推送到消息队列的末尾。

【讨论】:

  • dispatch != send...多么明显的区别/s。这只是浪费了我几个小时来追查为什么我的处理程序不工作。谢谢你,克里斯。
【解决方案2】:

我强烈建议您坚持使用AsyncTask(如果您需要旋转/背景支持,则使用 droid-fu 版本之一),除非您知道自己在做什么。它将帮助您清晰地跟踪 UI 线程中正在运行的代码以及后台任务中的代码,并避免您自己处理 Threads 和 Handlers 可能导致的很多混乱。

【讨论】:

  • 我一直在研究 AsyncTasks 与 Threads 的权衡。您知道为什么显示的示例不起作用吗?
  • 你的代码很乱,我们真的不知道那里发生了什么。至少我不能
  • 我坚持使用 Thread 有几个原因。我希望一个更简单的例子能得到帮助。我的问题是调用 dispatchMessage 而不是 sendMessage...oops
  • AsyncTask 确实没有“权衡”可言,而这些天我使用原始线程的唯一地方是当我正在处理不需要更新的任务时以任何方式完成时的 UI。如果您也想了解线程和处理程序,我真的建议您阅读 AsyncTask 的源代码。
【解决方案3】:

Handler 的 post 方法在参数中需要一个 Runnable 对象,并调度该可运行块的执行。相反,您可以使用 Handler.sendEmptyMessage() 或 Handler.sendMessage() 向 Handler 发送消息。所以将您的代码更改为以下内容:

Thread t = new Thread() {
            public void run() {
               _mResults = _interpreter.executeExpression("startup;",_mHandler);
                Message msg= _mHandler.obtainMessage();
                msg.obj= _mResults;
               _mHandler.sendMessage(msg);
           }
       };

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-02
    • 1970-01-01
    • 1970-01-01
    • 2015-11-11
    • 1970-01-01
    • 2015-01-10
    • 1970-01-01
    • 2019-10-09
    相关资源
    最近更新 更多