一、写在前面

  在Android中Handler首要被用于线程间切换,比方在子线程中拜访网络数据之后需求将数据更新到View中则需求使用到Handler进行数据处理

1、涉及到的类

  本篇文章会对如下几个类所涉及到的要害函数进行解析,以对Handler底层完成原理进行学习。

  • ActivityThread.java:当时使用进程发动的时分会调用到该类的main函数,在该函数中会创立UI线程的Looper目标并调用其loop函数以发动无限循环避免进程退出;
  • Looper.java:死循环调用MessageQueue中的next函数;
  • MessageQueue.java:Message入行列、出行列处理类,Looper中无限循环调用被堵塞就发生在该类的next函数中;
  • Handler.java:本篇文章主角类。

2、Handler简单使用

  如下以在UI线程中创立Handler为例,对Handler的使用进行简单的学习。

2.1 Handler定义

static class MyHandler extends Handler {
    @Override
    public void handleMessage(@NonNull Message msg) {
        ......
        //事务逻辑,当时逻辑处理则发生在UI线程中
    }
}

2.2 Handler使用

//以UI线程Looper目标创立Handler,假如在子线程使用Handler则可以先创立HandlerThread目标然后经过HandlerThread目标获取Looper目标
Handler handler = new MyHandler();
Message message = handler.obtainMessage();
message.what = 1;
message.obj = new Object();
//该函数调用则可以发生在子线程中
handler.sendMessage(message);

二、源码

  如下以ActivityThread->Looper->MessageQueue->Handler的次序对其间所涉及到的要害源码进行解析,当然有需求的也可以逆序看。

1、ActivityThread.main

  该函数作为当时使用进程的进口函数(参阅Android使用进程发动源码),其首先经过调用Looper.prepareMainLooper函数为当时进程的UI线程创立Looper目标,最后经过调用Looper.loop函数以避免进程无任务处理而退出,同时等候Handler发送Message进行处理。部分源码如下:

public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
    ......
    //为当时进程UI线程创立Looper目标
    Looper.prepareMainLooper();
    ......
    //避免进程死亡,同时等候Handler发送Message进行处理
    Looper.loop();
    //loop意外退出,一般情况下不会出现
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

2、Looper

2.1 preparexx

  经过调用如下函数中的其间一个则可以为当时线程成功创立Looper目标,并将创立好的Looper目标保存到ThreadLocal目标中。

  ThreadLocal:线程内部数据存储类。经过该类可以在指定的线程中存储数据,并只能在存储了对应数据的线程中才能正确获取到对应数据,其他线程则无法获取到该数据。

public static void prepareMainLooper() {
    //调用prepare函数创立Looper目标并保存到ThreadLocal目标中
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        //从ThreadLocal目标获取Looper目标
        sMainLooper = myLooper();
    }
}
public static void prepare() {
    prepare(true);
}
//quitAllowed:表明是否答应退出当时Looper,关于UI线程中的Looper而言则不答应退出
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    //创立Looper目标并保存到ThreadLocal目标中
    sThreadLocal.set(new Looper(quitAllowed));
}

2.2 结构函数

private Looper(boolean quitAllowed) {
    //创立MessageQueue目标给Handler使用
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

2.3 myLooper

//获取当时线程对应的Looper目标
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

2.4 loop

  当时线程(比方UI线程)经过调用该函数以避免进程退出。代码比较简单,中心便是经过for发动无限循环并调用函数loopOnce。

public static void loop() {
    //获取当时线程Looper目标
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    if (me.mInLoop) {
        Slog.w(TAG, "Loop again would have the queued messages be executed"
                + " before this one completed.");
    }
    ......
    me.mSlowDeliveryDetected = false;
    //死循环不断调用loopOnce函数
    for (;;) {
        if (!loopOnce(me, ident, thresholdOverride)) {
            return;
        }
    }
}

2.5 loopOnce

  如下代码省略掉了大部分不相关的函数完成。中心逻辑便是调用到函数MessageQueue.next(该函数会堵塞当时线程)以获取下一个可以处理的Meesage,并最终调用到Handler中进行事务逻辑处理。留意该处调用是发生在创立Looper目标的线程中(比方UI线程),这也是可以完成线程切换的重点。

private static boolean loopOnce(final Looper me,
        final long ident, final int thresholdOverride) {
    Message msg = me.mQueue.next();
    //假如没有Message需求处理而且没有被堵塞,则阐明上层事务方自动调用了quit函数而且当时looper可以退出
    //则完毕当时Looper
    if (msg == null) {
        return false;
    }
    ......
    try {
        //target对应Message的Handler目标,最终会调用到handleMessage函数
        msg.target.dispatchMessage(msg);
        if (observer != null) {
            observer.messageDispatched(token, msg);
        }
        dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
    } catch (Exception exception) {
        if (observer != null) {
            observer.dispatchingThrewException(token, msg, exception);
        }
        throw exception;
    } finally {
        ThreadLocalWorkSource.restore(origWorkSource);
        if (traceTag != 0) {
            Trace.traceEnd(traceTag);
        }
    }
    ......
    return true;
}

3、MessageQueue

3.1 next

  如下代码做了如下几件事情:(1)判别当时MessageQueue是否为空,假如为空则设置下次等候时刻为-1,即永久等候直到被唤醒停止;(2)假如不为空则判别行列首部Message是否抵达了处理时刻,假如到了则立马回来进行处理,不然计算等候时刻间隔,从头等候。

Message next() {
    final long ptr = mPtr;
    //判别是否初始化成功
    if (ptr == 0) {
        return null;
    }
    int pendingIdleHandlerCount = -1;
    //堵塞时刻,这儿有三个值
    //(1)0:不堵塞
    //(2)-1:堵塞,直到被唤醒停止
    //(3)>0:堵塞特定时刻之后自动唤醒
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
        //首次进来则不堵塞
        nativePollOnce(ptr, nextPollTimeoutMillis);
        synchronized (this) {
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            //获取当时Message行列
            Message msg = mMessages;
            //一般情况下msg.target不会为空,因而这儿暂时不看
            if (msg != null && msg.target == null) {
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                //判别当时时刻是否小于行列首部Message时刻,假如小于则阐明不存在Message需求处理
                //留意Message行列首部时刻最小,越往后时刻越晚
                if (now < msg.when) {
                    //获取最近需求处理Message时刻间隔当时时刻间隔,以计算下次需求等候时刻
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                //存在Message抵达处理时刻
                } else {
                    mBlocked = false;
                    //目前剖析情况下prevMsg为Null
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        //移除即将被处理的行列头部Message
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    //设置当时Message正在被处理flag
                    msg.markInUse();
                    //回来行列首部Message进行处理
                    return msg;
                }
            //Message行列为空,因而将等候时刻设置为-1(即永久等候直到被唤醒停止)    
            } else {
                nextPollTimeoutMillis = -1;
            }
            if (mQuitting) {
                dispose();
                return null;
            }
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                //阐明需求其他地方来进行唤醒,比方首个Message进入行列的时分
                mBlocked = true;
                continue;
            }
            ......
        nextPollTimeoutMillis = 0;
    }
}

3.3 enqueueMessage

  如下代码首要便是按照时刻先后次序将当时Message刺进到MessageQueue的指定节点处。MessageQueue中的节点Message对应处理时刻是头部->尾部依次递增的。

boolean enqueueMessage(Message msg, long when) {
    //不答应Message对应Handler目标为null
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    synchronized (this) {
        //当时Message正在被处理或许正在入行列,在上述next函数中有相关标记代码
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }
        //当时Looper正在退出
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }
        //表明当时Message正在入行列
        msg.markInUse();
        //Message处理时刻,用于后续入行列以及设置等候时刻
        msg.when = when;
        //当时Message行列
        Message p = mMessages;
        //是否需求自动唤醒next函数中的堵塞
        boolean needWake;
        //阐明当时Message是第一条Message,因而需求自动唤醒
        if (p == null || when == 0 || when < p.when) {
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            //p.target一般不会为null,因而这儿为false
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                //需求刺进节点的前一个节点
                prev = p;
                //需求刺进到哪个节点之前
                p = p.next;
                //成功找到需求刺进到哪个节点之前或许到了行列尾部
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            //刺进到行列中
            msg.next = p;
            prev.next = msg;
        }
        //判别是否自动唤醒next函数中的堵塞,第一次进来一般都需求自动唤醒
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

4、Handler

4.1 enqueueMessage

  Handler中有多个函数都可以将Message刺进到MessageQueue中,不过最终都会调用到enqueueMessage函数中。代码如下:

/**
* queue:从当时线程Looper目标中获取
* msg:需求入行列的Message目标
* uptimeMillis:Message处理时刻,SystemClock.uptimeMillis() + 延迟时刻,或许事务方传递
*/
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
        long uptimeMillis) {
    //当时Handler目标
    msg.target = this;
    msg.workSourceUid = ThreadLocalWorkSource.getUid();
    //默以为false
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    //将Message加入到MessageQueue中
    return queue.enqueueMessage(msg, uptimeMillis);
}

4.2 dispatchMessage

  如下代码便是Looper.loopOnce最终调用到的代码了。其首先会判别处理的Message目标和当时Handler目标是否存在CallBack,假如存在则优先调用CallBack目标,不然调用到当时Handler的handleMessage函数。

public void dispatchMessage(@NonNull Message msg) {
    //判别Message是否设置了CallBack,经过调用Handler中的postxx函数进行设置。
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        //判别当时Handler是否设置了CallBack(可经过Handler结构函数传入,hook ActivityThread中Handler目标重点)
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //假如Message和Handler都没有设置CallBack则调用到handleMessage,后续就走到了咱们的事务逻辑。
        handleMessage(msg);
    }
}

三、总结

  如上即为Handler底层大致源码了,其可以完成线程间切换的首要原理便是创立Looper目标的线程(比方UI线程)会不断循环(假如没有Message获取Message处理时刻未到则会被堵塞)读取MessageQueue中是否有需求处理的Message,假如有则将需求处理的Message发送给Handler进行处理;而其他子线程则只需求经过对应的Handler目标将需求处理的Message刺进到MessageQueue即可。

  总之一句话,Handler中处理的事务逻辑最终运行在哪个线程中,取决于创立Handler时传递进去的Looper目标在哪个线程中被创立成功之后调用其loop函数。