52

要从其他线程更新 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)
    

您也可以使用 AsyncTask,但我的问题更侧重于更新一个非常简单的组件的用例。让我们看看如何使用这两种方法来完成:

  1. 使用可运行文件:

    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?
        }
    

恕我直言,消息不是要走的路,因为:

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

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

那么使用 Messages 而不是 Runnables 有什么优势呢?在现代 Android 编程中,消息是否被推到了后台?有什么可以用 Runnables 做不到的 Messages 做的吗?

提前致谢。

4

4 回答 4

22

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

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 代码 - 处理程序

于 2014-03-20T13:08:17.723 回答
15

Messages可以重用,因此它会导致创建的对象和 GC 更少。您最终也会得到更少的类和匿名类型。

一个很大的优势是发送 aMessage到 a的类Handler不需要知道关于 that 的实现的任何信息Message。这可以帮助封装,具体取决于它的使用位置。

最后考虑清洁度的区别

mHandler.obtainMessage(DO_STUFF, foo).sendToTarget();

对比

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

如果您有几个地方需要doStuff(),那么前者的可读性更高,并且您的代码重复更少。

于 2013-11-25T23:27:58.890 回答
4

HandlerrunOnUiThread()根据文档,接口提供的功能比 多得多:

处理程序有两个主要用途:
(1) 安排消息和可运行文件在未来某个时间点执行
(2) 将要在与您自己的线程不同的线程上执行的操作排入队列。

runOnUiThread只做 (2) 的一个子集。即“将要在UI 线程上执行的操作排入队列”

因此,除非您需要那些额外的功能,否则 IMOrunOnUiThread是足够且首选的方式。

于 2012-06-26T13:27:01.563 回答
2

I prefer Runnable to Message. I think code using Runnable is much clearer than Message, because the event handling code is very close to the event. Also, You can avoid the overhead of defining constants and switch cases.

And I don't think using Runnable violates encapsulation. You can extract the code in Runnable.run() into another method in the outer class, for example on...Event(), or even wrap it into an EventHandler object. Both ways are much clearer than using Message, especially when you need store references in Message, because using Runnable avoids downcasting msg.obj. And the nameless field msg.obj is also error prone and sometimes inefficient to understand.

And Runnable can also be reused by storing it as a field.

于 2016-08-23T08:59:19.393 回答