学习并理解 handler,looper,message之间的关系

本文详细解析了Android中Handler、Looper及MessageQueue的工作原理及其相互关系,包括如何在一个线程中创建Looper,Handler如何发送消息,以及消息如何被处理。

学习并理解 handler,looper,message之间的关系
先看 Looper 源代码

private Looper() {  **//3,创建Looper**
// 创建一个新的消息队列
    mQueue = new MessageQueue();

    mRun = true;

// 将创建的looper和当前线程绑定在一起
    mThread = Thread.currentThread();
}


public static final void prepare() { //2,调用prepare()

// 这个判断保证一个线程只能有一个looper
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
// 创建一个looper存放在 ThreadLocal 中, ThreadLocal 的作用就是保证每个线程操作都是自己的对象
    sThreadLocal.set(new Looper()); //3,创建Looper
}


public static final void prepareMainLooper() {// 1, 调用此方法创建 一个Looper

    prepare(); // 2,调用prepare()
    setMainLooper(myLooper());
    if (Process.supportsProcesses()) {
        myLooper().mQueue.mQuitAllowed = false;
    }
}

public static final void loop() { // 4,loop方法

// 获取之前放在 ThreadLocal 中创建的 Looper对象和消息队列
    Looper me = myLooper();
    MessageQueue queue = me.mQueue;
    .....
    while (true) {
    // 代码执行到这里会阻塞。。。 这时候跳到 第二大步骤
        Message msg = queue.next(); // might block

        if (msg != null) {
            if (msg.target == null) {
                // No target is a magic identifier for the quit message.
                return;
            }
           ....
            msg.target.dispatchMessage(msg); // 这个msg.target就是handler,用来区分不同的handler。
           ....
        }
    }
}

public static final Looper myLooper() {
    return (Looper)sThreadLocal.get();
}

一,首先一个程序的启动时,他的UI线程(也就是主线程)会在main 方法中调用 Looper的静态方法

# ActivityThread.java 主线程中的部分代码

public static final void main(String[] args) {

.....
// 1, 调用此方法创建 一个Looper
    Looper.prepareMainLooper();

    if (sMainThreadHandler == null) {
        sMainThreadHandler = new Handler();
    }

    ActivityThread thread = new ActivityThread();
    thread.attach(false);
.....
// 4,调用此死循环方法不断的从消息队列中读取消息。
    Looper.loop();

}

二,关于handler,搞清楚前面的Looper 后 再来看看handler是怎么工作的
当我们在activity中创建handler写下下面代码时。
private Handler handler = new Handler() {

    @Override
    public void handleMessage(Message msg) {}

}

来看看他的构造函数
public Handler() {
….
// 这里又调用到了Looper.myLooper()方法,这里得到了UI线程之前创建的Looper。
mLooper = Looper.myLooper();
….
// 此处获得UI线程创建的消息队列
mQueue = mLooper.mQueue;
mCallback = null;
}

可以看到通过Handler() 构造函数 ,新建的handler对象和Looper对象,消息队列绑定在一起了。

总结 一,二 两大步骤可以知道 一个线程里面只有一个looper 和messagequeue,我们有时在activity中却可以创建多个handler的对象发送

消息,那么looper是如何识别不同的handler对象呢,最后跳到第三大步,发送message。

三,我们一般都会开启一个子线程进行一些耗时操作,然后在子线程中发送消息到主线程,主线程在执行更新ui的操作。
当我们使用handler.sendMessage(msg)时,看看handler的源码

public void handleMessage(Message msg) {

}

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

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

public final boolean sendMessageDelayed(Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    boolean sent = false;
    // 得到消息队列
    MessageQueue queue = mQueue;
    if (queue != null) {
        // 将当前发送message的对象赋值给msg.target属性,这个属性就是用来区分不同的handler
        msg.target = this;
        // 调用messagequeue的方法
        sent = queue.enqueueMessage(msg, uptimeMillis);
    } else {
        RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
    }
    return sent;
}

可以看到 最后调用sendMessageAtTime()这个方法,再来看看这个方法
得到消息队列
MessageQueue queue = mQueue;
if (queue != null) {
// 将当前发送message的对象赋值给msg.target属性,这个属性就是用来区分不同的handler
msg.target = this;
// 调用messagequeue的方法,
sent = queue.enqueueMessage(msg, uptimeMillis);
最后调用queue.enqueueMessage()方法,将消息添加到消息队列

来看看 MessageQueue.enqueueMessage 代码

final boolean enqueueMessage(Message msg, long when) {
    ...
        Message p = mMessages;
        if (p == null || when == 0 || when < p.when) {
            // 当前发送的message需要马上被处理调,needWake唤醒状态置true
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked; // new head, might need to wake up
        } else {
            // 当前发送的message被排队到其他message的后面,needWake唤醒状态置false
            Message prev = null;
            while (p != null && p.when <= when) {
                prev = p;
                p = p.next;
            }
            msg.next = prev.next;
            prev.next = msg;
            needWake = false; // still waiting on head, no need to wake up
        }
    }
    // 是否唤醒主线程
    if (needWake) {
        nativeWake(mPtr);
    }
    return true;

}

当handler.sendMessage(msg)完成后,之前的UI线程的loop方法中 Message msg = queue.next()就不会再阻塞了,会依次执行下去
当执行到 msg.target.dispatchMessage(msg);方法时。可以看到hanlder源码最终执行的是 handleMessage()。而我们新建的handler 又重

写了这个方法。从而在主线程进行一些ui操作。

小结下,总的来说就是ui线程会在程序启动时,创建looper和消息队列,然后调用Looper的静态方法 loop(),这个方法中 message msg =

queue.next();//如果里面没有消息就会阻塞。如果Handler在主线程中创建,Looper会在死循环里等待取消息,1、没取到,就阻塞,2、一

旦被子线程唤醒,取到消息,就把Message交给Handler处理。子线程用Handler去发送消息,拿写入描述符去写消息,唤醒主线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值