用 Looper.getMainLooper() 初始化的处理程序不响应消息回调

Posted

技术标签:

【中文标题】用 Looper.getMainLooper() 初始化的处理程序不响应消息回调【英文标题】:Handlers initialized with Looper.getMainLooper() does not respond to message callbacks 【发布时间】:2013-03-10 09:59:45 【问题描述】:

我正在尝试实现从不同线程监听同一个 Looper 的处理程序。

下面我有两个处理程序,一个在主线程中创建,另一个在子线程中创建,但是两者都被初始化为在 Main Looper 上侦听。

private Handler mMain;
public static final ThreadPoolExecutor tpe =
        (ThreadPoolExecutor) Executors.newCachedThreadPool();

@Override
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mMain = new Handler(Looper.getMainLooper()) 
        @Override
        public void handleMessage(Message msg) 
            Log.wtf("", "main:" + msg);
        
    ;

    tpe.execute(new Runnable() 
        private Handler tChild = new Handler(Looper.getMainLooper()) 
            @Override
            public void handleMessage(Message msg) 
                Log.wtf("", "child:" + msg);
            
        ;

        @Override
        public void run() 
            Log.wtf("", "send msg to main looper");
            tChild.sendEmptyMessage(100);
        
    );

但是当我发送如下消息时,只有子处理程序会打印消息。主处理程序没有收到消息。

03-20 22:02:26.754: A/(12857): send msg to main looper
03-20 22:02:26.847: A/(12857): child: what=100 when=-8ms 

我做错了什么?感谢您的阅读。

【问题讨论】:

【参考方案1】:

每个Handler 实例都控制Message 目标,无法让它们共享,因此发送到Handler 的每条消息或帖子都只能由该实例执行。

Looper 表示哪个线程发送的消息/runnables 将在哪个线程上执行。在您的代码中,两个处理程序都将在主线程上执行handleMessage(),尽管它们是在单独的线程上创建的。这就是你可以将Looper 实例传递给Handler 的真正原因...如果你没有传递Looper那么Handler 将在它所在的线程上执行代码已创建(必须也是Looper 线程)。

此外,因此没有理由创建多个处理程序以这种方式发布数据。单个Handler 被设计为从多个线程发送消息,它们都在MessageQueue 中序列化并在选定的Looper 线程上执行。您可以从后台线程直接发布到mMain 以在该线程上执行代码。在这种情况下,传递Looper 是多余的,因为代码已经在主线程上。

【讨论】:

我明白了,谢谢!假设有一天 Runnable 是一个外部类而不是一个内部类,我应该通过它的构造函数将一个初始化的 Handler 传递给它,对吧? 架构将依赖于应用程序,但您需要从计划向其发布消息的任何位置引用 Handler 为什么不在Application上下文(扩展Application的类)中只使用一个Handler(this.getMainLooper())?这难道不会比在 Activity 中进行更清洁吗?【参考方案2】:

发送到Handler 的消息将仅由该Handler 处理,即使它正在共享Looper

Handler的源码中埋藏着一行

msg.target = this;

这确保没有其他Handler 会碰它。

【讨论】:

以上是关于用 Looper.getMainLooper() 初始化的处理程序不响应消息回调的主要内容,如果未能解决你的问题,请参考以下文章

handler

Android 判断当前thread 是否是UI thread

runOnUiThread方法和Handler有什么区别?哪一个最好用?

在Service中弹出Toast和Dialog

20180710

安卓面试集锦