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

来源:互联网 发布:latex mac下载官网 编辑:程序博客网 时间:2024/05/16 17:31

学习并理解 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去发送消息,拿写入描述符去写消息,唤醒主线程。

1 0
原创粉丝点击