Handler机制梳理

    在android中handler机制中再常见不过了,用于异步处理,像项目中经常会在子线程中进行IO(网络 文件读写 数据库读写等)耗时操作,完成之后需要在UI线程进行界面更新,这种情况就需要用到Handler,来起到这种桥梁链接的作用。

    OK,那我会问你,handler的内部机制是怎样?

    答:handler会创建消息队列MessageQueue和Looper,当我们在子线程中发送sendMessage(Message msg)时,会加入到消息队列中,Looper会进行不断的消息循环,拿到加入的消息,进行dispatchMessage,进而会走到handler中的handlerMessage()方法中去,这样就切换到主线程了。

    上面的回答完了,但其实是不严谨或者说内部很多细节没有讲到,换句话说就是对hanlder还了解的不够深入,例如随便问你几个问题,1.MessageQueue和Looper什么时候创建的。2.handler内部是如何获取到当前线程的Looper。3.MessageQueue存储消息是采用队列的形式来存储吗。4.如何在子线程中创建一个handler。

    下面结合具体的源码来进行讲解。

    1:MessageQueue和Looper创建的时机

    这要从ActivityThread中的main()方法讲起,代码如下

 1 public static void main(String[] args){
 2    .....
 3    //创建looper和messagerQueue
 4    Looper.prepareMainLooper();
 5
 6    ActivityThread thread = new ActivityThread();
 7    thread.attach(false, startSeq);
 8    .....
 9    if (false) {
10        Looper.myLooper().setMessageLogging(new
11                LogPrinter(Log.DEBUG, "ActivityThread"));
12    }
13    //开启消息循环
14    Looper.loop();
15}

可以这样理解在app应用启动的时候,就会创建looper和messageQueue,创建looper实例对象,同时MessagerQueue以成员变量的形式存在,同时会对looper进行设置ThreadLocal.set(looper),这个方法为后接下来的“handler内部如何获取到当前线程的Looper”提供了依据。

    

1.1 创建looper

 1public static void prepareMainLooper() {
 2   //准备创建looper
 3    prepare(false);
 4    synchronized (Looper.class) {
 5        if (sMainLooper != null) {
 6            throw new IllegalStateException("The main Looper has already been prepared.");
 7        }
 8        sMainLooper = myLooper();
 9    }
10}

1.2 threadlocal设置looper

1private static void prepare(boolean quitAllowed) {
2    if (sThreadLocal.get() != null) {
3        throw new RuntimeException("Only one Looper may be created per thread");
4    }
5    //threadLocal设置looper
6    sThreadLocal.set(new Looper(quitAllowed));
7}

1.3 looper构造方法

1private Looper(boolean quitAllowed) {
2   //looper构造方法,创建messagerQueue
3    mQueue = new MessageQueue(quitAllowed);
4    mThread = Thread.currentThread();
5}

    2. handler内部是如何获取到当前线程的Looper。

    handler内部为什么需要获取looper呢,是因为hanlder.sendMessager(Messager)时需要拿到MessageQueue,把消息加入到队列中去。不同线程的handler如何拿到looper,是根据ThreadLocal为依据的,ThreadLocal并不是线程,它的作用是可以在每个线程中互不干扰地存储并提供数据,通过ThreadLocal可以轻松获取每个线程的looper。

    当我们创建handler的时候,会走到如下的构造方法中去:

 1public Handler(Callback callback, boolean async) {
 2    ......
 3   //拿到looper
 4    mLooper = Looper.myLooper();
 5    if (mLooper == null) {
 6        //熟悉的代码,在子线程中创建handler,需要调用prepare()方法,否则报这个错误
 7        throw new RuntimeException(
 8            "Can't create handler inside thread that has not called Looper.prepare()");
 9    }
10   //拿到looper对应的messageQueue
11    mQueue = mLooper.mQueue;
12   ........
13}

    

此时要进入到Looper.mylooper()方法内部才可以看到“真相”

1public static @Nullable Looper myLooper() {
2    //与之前的threadLocal.set(looper)遥相呼应
3    return sThreadLocal.get();
4}

    

    至此handler内部就拿到了在ActivityThread中创建的looper(MessageQueue),从而可以进行sendMessager(),加入消息队列中去。

    发送消息:

 1public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
 2    //通过looper拿到消息队列
 3    MessageQueue queue = mQueue;
 4    if (queue == null) {
 5        RuntimeException e = new RuntimeException(
 6                this + " sendMessageAtTime() called with no mQueue");
 7        Log.w("Looper", e.getMessage(), e);
 8        return false;
 9    }
10   //加入消息队列
11    return enqueueMessage(queue, msg, uptimeMillis);
12}

    加入消息队列:

1private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
2   //把handler的引用赋值给msg.target对象,为后期的MessagerQueue读消息,
3  //进行dispathMessager(),可以拿到对应的handler对象
4    msg.target = this;
5    if (mAsynchronous) {
6        msg.setAsynchronous(true);
7    }
8    return queue.enqueueMessage(msg, uptimeMillis);
9}

    3. MessageQueue存储消息是采用队列的形式来存储吗。

    答案:不是。MessagerQueue是采用单链表来存储的。

    单链表形式来存储你加入的消息队列

 1boolean enqueueMessage(Message msg, long when) {
 2       ......
 3        msg.markInUse();
 4        msg.when = when;
 5        Message p = mMessages;
 6        boolean needWake;
 7        if (p == null || when == 0 || when < p.when) {
 8            // New head, wake up the event queue if blocked.
 9            msg.next = p;
10            mMessages = msg;
11            needWake = mBlocked;
12        } else {
13            .......
14            needWake = mBlocked && p.target == null && msg.isAsynchronous();
15            Message prev;
16            for (;;) {
17                prev = p;
18                p = p.next;
19                if (p == null || when < p.when) {
20                    break;
21                }
22                if (needWake && p.isAsynchronous()) {
23                    needWake = false;
24                }
25            }
26            msg.next = p; // invariant: p == prev.next
27            prev.next = msg;
28        }
29
30        // We can assume mPtr != 0 because mQuitting is false.
31        if (needWake) {
32            nativeWake(mPtr);
33        }
34    }
35    return true;
36}

    next()方法会返回这条消息并将其从单链表中删除。

 1Message next() {
 2    .......
 3    for (;;) {
 4        ......
 5        synchronized (this) {
 6           ......
 7            Message prevMsg = null;
 8            Message msg = mMessages;
 9            if (msg != null && msg.target == null) {
10                // Stalled by a barrier.  Find the next asynchronous message in the queue.
11                do {
12                    prevMsg = msg;
13                    msg = msg.next;
14                } while (msg != null && !msg.isAsynchronous());
15            }
16            if (msg != null) {
17                if (now < msg.when) {
18                    // Next message is not ready.  Set a timeout to wake up when it is ready.
19                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
20                } else {
21                    // Got a message.
22                    mBlocked = false;
23                    if (prevMsg != null) {
24                        prevMsg.next = msg.next;
25                    } else {
26                        mMessages = msg.next;
27                    }
28                    msg.next = null;
29                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
30                    msg.markInUse();
31                    return msg;
32                }
33            }       
34        }
35    }
36}

    next()什么时候会被调用呢,在loop()中会一直被调用,不断的进行循环。

 1public static void loop() {
 2    //通过threadLocal拿到looper
 3    final Looper me = myLooper();
 4    if (me == null) {
 5        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
 6    }
 7    //通过looper拿到消息队列
 8    final MessageQueue queue = me.mQueue;
 9    .......
10    for (;;) {
11        Message msg = queue.next(); // might block
12        if (msg == null) {
13            // No message indicates that the message queue is quitting.
14            return;
15        }
16      .......
17        try {
18           //msg.target即为handler,进入到handler.dispathMessager(msg)方法中去
19            msg.target.dispatchMessage(msg);
20            end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
21        } finally {
22            if (traceTag != 0) {
23                Trace.traceEnd(traceTag);
24            }
25        }
26        .........
27    }
28}

    执行handleMessager(msg)方法

 1public void dispatchMessage(Message msg) {
 2    if (msg.callback != null) {
 3        //设置了callback
 4        handleCallback(msg);
 5    } else {
 6        if (mCallback != null) {
 7            if (mCallback.handleMessage(msg)) {
 8                return;
 9            }
10        }
11       //走入到我们常见的handleMessage(msg)方法中去了
12        handleMessage(msg);
13    }
14}

    4.如何在子线程中创建一个handler。

    思考:为什么在主线程中创建handler不需要Looper.prepare()和Looper.loop()。

 1public void createHandlerInThread(){
 2    new Thread("Thread#2"){
 3        @Override
 4        public void run() {
 5            //在子线程需要通过该方法手动创建looper和messageQueue
 6            Looper.prepare();
 7            Handler handler = new Handler(){
 8                @Override
 9                public void handleMessage(Message msg) {
10                    super.handleMessage(msg);
11                }
12            };
13            //开启消息循环
14            Looper.loop();
15        }
16    };
17}

     答案在ActivityThread类中main()方法中。

最后附上一张整体流程图:

发布了6 篇原创文章 · 获赞 5 · 访问量 455

猜你喜欢

转载自blog.csdn.net/kaibingwang/article/details/89892335