更新GUI:Runnables vs Messages

时间:2012-06-26 13:12:09

标签: android user-interface message runnable

要从其他线程更新GUI,基本上有两种主要方法:

  1. 将java.lang.Runnable与以下任何方法一起使用:

    Activity.runOnUiThread(Runnable)
    View.post(Runnable)
    View.postDelayed(Runnable, long)
    Handler.post(Runnable)
    
  2. 使用android.os.Message:

    Handler.sendMessage(Message) / Handler.handleMessage(Message)
    
  3. 您也可以使用AsyncTask,但我的问题更侧重于更新非常简单的组件的用例。让我们看看如何使用这两种方法完成:

    1. 使用Runnables:

      TextViev tv = ...;
      final String data = "hello";
      Runnable r = new Runnable() {
      
          @Override
          public void run(){
              tv.setText(data);
          }
      
      };
      //Now call Activity.runOnUiThread(r) or handler.post(r), ...
      
    2. 使用消息:

      Message m = handler.obtainMessage(UPDATE_TEXT_VIEW, "hello");
      handler.sendMessage(m);
      
      //Now on handler implementation:
          @Override
          public void handleMessage(Message msg) {
              if(msg.what == UPDATE_TEXT_VIEW){
                  String s = (String) msg.obj;
                  tv.setText(data);
              } ... //other IFs?
          }
      
    3. 恕我直言,消息不是要走的路,因为:

      • 对于新的非android程序员来说不容易理解(在构造期间处理程序挂钩到它的线程)。
      • 如果消息跨越进程边界,则对象有效负载应为Parcellable。
      • 重复使用邮件(如果没有正确清理,则容易出错?)
      • 处理程序具有双重角色(它发送消息,但也处理它们)
      • 消息属性是公共的,但也提供getter / setter。

      另一方面,Runnables遵循众所周知的命令模式,对程序员更友好,更易读。

      那么使用Messages over Runnables有什么好处?在现代Android编程中,消息是否被推入后台?有什么可以用Runnables无法完成的消息吗?

      提前致谢。

4 个答案:

答案 0 :(得分:20)

我想说使用MessageRunnable之间没有什么区别。它主要归结为个人偏好。为什么?查看源代码,您会发现发布Runnable使用相同的确切消息传递机制。它只是将Runnable附加到Message并发送。

4.4.2源代码

public final boolean post(Runnable r) {
    return  sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

参考:Grep Code - Handler

答案 1 :(得分:12)

Messages可以重复使用,因此可以减少创建的对象数量,减少GC的使用量。您最终也会减少类和匿名类型。

一个很大的优势是,向Message发送Handler的班级不需要了解Message的实施情况。这有助于封装,具体取决于它的使用位置。

最后考虑

之间的清洁差异
mHandler.obtainMessage(DO_STUFF, foo).sendToTarget();

VS

final Foo tempFoo = foo;
mHandler.post(new Runnable(){
    @Override
    public void run(){
        doStuff(tempFoo);
    }
};

如果你有几个地方需要doStuff(),前者的可读性更高,你的代码重复次数也会减少。

答案 2 :(得分:4)

根据文档:

Handler界面提供了比runOnUiThread()更多的功能

  

Handler有两个主要用途:
  (1)安排消息和runnables作为将来的某个点执行   (2)将要在不同于自己的线程上执行的动作排入队列。

runOnUiThread只做(2)的子集。 ie"将要执行的操作排入 UI线程 "

所以IMO除非你需要那些额外的功能runOnUiThread是充分和首选的方式。

答案 3 :(得分:2)

我更喜欢RunnableMessage。我认为使用Runnable的代码比Message更清晰,因为事件处理代码非常接近事件。此外,您可以避免定义常量和切换案例的开销。

我不认为使用Runnable会违反封装。您可以将Runnable.run()中的代码提取到外部类中的另一个方法中,例如on...Event(),或者甚至将其包装到EventHandler对象中。两种方式都比使用Message更清晰,尤其是当您需要Message中的商店引用时,因为使用Runnable可以避免向下转换msg.obj。无名字段msg.obj也容易出错,有时也无法理解。

Runnable也可以通过将其存储为字段来重复使用。