如何通过Handler更新UI

时间:2010-11-09 15:41:56

标签: android multithreading

所以,我收到一个错误,我正在从错误的线程更新UI。这当然不是我的意图。我的案子很长,但我会尝试用代码片段做正义。我的最终目标是在一个单独的线程中运行一个昂贵的任务,并发布在路上和最后发生到我的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();

   ); 

然后在inpterpreter中我这样做:

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,我知道这是非法的。那么,我做错了什么?

谢谢!

3 个答案:

答案 0 :(得分:3)

_mHandler.dispatchMessage(msg);

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

  

dispatchMessage(消息消息)

     

在此处理系统信息。

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

  

sendMessage(消息消息)

     

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

答案 1 :(得分:2)

我强烈建议您坚持使用AsyncTask(或者如果您需要轮换/背景支持,请使用droid-fu版本之一),除非您知道自己正在进行什么。它将帮助您清晰地跟踪UI线程中正在运行的代码以及后台任务中的代码,并为您节省很多与自己处理ThreadHandler的混淆。可能导致。

答案 2 :(得分:1)

Handler的post方法需要参数中的Runnable对象,并调度该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);
           }
       };