线程 (Handler、Looper、MessageQueue和Thread的理解)

本文详细解析了Android中Handler、Message、MessageQueue和Looper的工作原理及它们之间的关系。Handler用于发送和处理消息,Message作为消息载体,MessageQueue管理消息队列,Looper从队列中取出消息并派发给Handler。每个Looper对应一个MessageQueue,一个线程对应一个Looper,而一个Looper可以有多个Handler。在主线程中,如果不指定Looper,Handler将默认使用主线程的Looper。在其他线程中,需手动创建并启动Looper以使Handler能正常工作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、先看下他们各自的用途

Handler:负责Message消息的发送与处理;

Message:消息载体,实现Parcelable接口;

MessageQueue:消息队列,对消息进行管理;

Looper:消息泵,不断的从MessageQueue消息队列中获取消息并派发到对应的Handler中进行处理;

Thread:线程,整个消息的调度是在这进行的。

二、实现过程

①创建消息

//创建一个消息实体

Message msg = Message.obtain(mHandler);

//对消息实体赋值

msg.what = 1;

//发送到对应的Handler(即在创建消息实体传入的mHandler)进行处理

msg.sendToTarget();

②消息传递过程

上面的sendToTarget会传递到Handler中

 public final boolean sendMessage(Message msg)
 {
        return sendMessageDelayed(msg, 0);
}

这里后面有调用到了

    public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;
        if (queue != null) {
            msg.target = this;
            sent = queue.enqueueMessage(msg, uptimeMillis);
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
        }
        return sent;
    }

这里我们注意到,他将我们这个消息加入到了MessageQueue中,并且这个message的target设置为this,目的是为了在处理消息环节,Message能找到正确的Handler

我们上面有说到消息是MessageQueue中的消息是通过Looper来传输到对应的 handler中处理的

  while (true) {
            Message msg = queue.next(); // might block
    //中间省略了些代码
            if (msg != null) {

//注意这里,我们将消息派发给刚才传入的this即外面的那个mHandler
                msg.target.dispatchMessage(msg);
            }
        }

那我们就来看看Handler里面的dispatchMessage做了什么

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

这里如果没有Callback就直接调用handleMessage(msg)进行处理了(handleMessage在handler实现类中都有处理)

那这个Callback是做什么用的呢?我们知道消息传递有同步也有异步 或者定时,那这个Callback就是保持传入的Runnable用的

    public final boolean postDelayed(Runnable r, long delayMillis)
    {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }

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

这样呢  我们就能在收到消息的时候调用runnable了。

这样我们就明白了他们直接的关系了:

·      Handler的处理过程运行在创建Handler的线程里

·      一个Looper对应一个MessageQueue

·      一个线程对应一个Looper

·      一个Looper可以对应多个Handler

·      不确定当前线程时,更新UI时尽量调用post方法

这里还有个问题我们需要注意:

在主线程(UI线程)里,如果创建Handler时不传入Looper对象,那么将直接使用主线程(UI线程)的Looper对象(系统已经帮我们创建了);在其它线程里,如果创建Handler时不传入Looper对象,那么,这个Handler将不能接收处理消息。在这种情况下,通用的作法是:

class thread extends Thread

{

public Handler mHandler;

public void run()

{

Looper.prepare();

mHandler = new Handler() {

public void handlerMessage(Message msg) {

}

};

Looper.loop();

}

}

在创建Handler之前,为该线程准备好一个LooperLooper.prepare),然后让这个Looper跑起来(Looper.loop),抽取Message,这样,Handler才能正常工作。

因此,Handler处理消息总是在创建Handler的线程里运行。而我们的消息处理中,不乏更新UI的操作,不正确的线程直接更新UI将引发异常。因此,需要时刻关心Handler在哪个线程里创建的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值