美文网首页
Android Handler 源码分析

Android Handler 源码分析

作者: 是刘航啊 | 来源:发表于2021-01-12 10:30 被阅读0次
    前言

    文章是记录自己研究源码的过程,方便日后的回顾,文章可能篇幅过长。

    Handler 基本使用
    private Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            mTextView.setText((String) msg.obj);
            return false;
        }
    });
    
    new Thread(new Runnable() {
       @Override
       public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Message message = Message.obtain();
            message.obj = "Handler Message";
            handler.sendMessage(message);
        }
    }).start();
    

    源码分析

    Handler -> sendMessage
    public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }
    
    Handler -> sendMessageDelayed
    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    
    Handler -> sendMessageAtTime
    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    
    Handler -> enqueueMessage
    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
                long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();
    
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
    

    这里将 Handler 赋值给 msg.target
    queue.enqueueMessage() -> MessageQueue.enqueueMessage()

    MessageQueue -> enqueueMessage
    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
                throw new IllegalArgumentException("Message must have a target.");
        }
    
        synchronized (this) {
            if (msg.isInUse()) {
                throw new IllegalStateException(msg + " This message is already in use.");
            }
            
            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;
            }
            
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                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; // invariant: p == prev.next
                prev.next = msg;
            }
            
            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }
    
    修改一下代码
    Message message1 = Message.obtain();
    message1.obj = "Handler Message1";
    handler.sendMessage(message1);
    
    Message message2 = Message.obtain();
    message2.obj = "Handler Message2";
    handler.sendMessageDelayed(message2, 1000);
    
    Message message3 = Message.obtain();
    message3.obj = "Handler Message3";
    handler.sendMessageDelayed(message3, 500);
    

    发送 3 条消息,然后来分析 enqueueMessage 里的代码

    MessageQueue -> enqueueMessage ( message1 )
    boolean enqueueMessage(Message msg, long when) {
        ...
        msg.when = when;//注释 1
        Message p = mMessages;//注释 2
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;//注释 3
            mMessages = msg;//注释 4
            needWake = mBlocked;
        } else {
            ...
        }
        ...
    }
    

    当发送 message1 消息时,mMessages 是还没有赋值的,所以会执行 if 内的代码片段
    注释 1 : message1.when = 0
    注释 2 : Message p = null
    注释 3 : message1.next = null
    注释 4 : mMessages = message1

    MessageQueue -> enqueueMessage ( message2 )
    boolean enqueueMessage(Message msg, long when) {
        ...
        msg.when = when;//注释 1
        Message p = mMessages;//注释 2
        if (p == null || when == 0 || when < p.when) {
            ...
        }  else  {
            ...
            Message prev;
            for (;;) {
                   prev = p;//注释 3
                   p = p.next;//注释 4
                   if (p == null || when < p.when) {
                       break;
                   }
                   if (needWake && p.isAsynchronous()) {
                       needWake = false;
                   }
               }
               msg.next = p; // invariant: p == prev.next //注释 5
               prev.next = msg;//注释 6
        }
        ...
    }
    

    注释 1 : message2.when = 1000
    注释 2 : Message p = message1
    注释 3 : prev = message1
    注释 4 : message1 = null
    注释 5 : message2.next = message1
    注释 6 : message1.next = message2

    MessageQueue -> enqueueMessage ( message3 )
    boolean enqueueMessage(Message msg, long when) {
        ...
        msg.when = when;//注释 1
        Message p = mMessages;//注释 2
        if (p == null || when == 0 || when < p.when) {
            ...
        }  else  {
            ...
            Message prev;
            for (;;) {
                   prev = p;//注释 3
                   p = p.next;//注释 4
                   if (p == null || when < p.when) {//注释5
                       break;
                   }
                   if (needWake && p.isAsynchronous()) {
                       needWake = false;
                   }
               }
               msg.next = p; // invariant: p == prev.next //注释 6
               prev.next = msg;//注释 7
        }
        ...
    }
    

    注释 1 : message3.when = 500
    注释 2 : Message p = message1
    注释 3 : prev = message1
    注释 4 : message1 = message2
    注释 5 : 500 < 1000 跳出循环
    注释 6 : message3.next = message2
    注释 7 : message1.next = message3

    所以可以得出一个结论
    • Message 是一个链表
    • Message 中通过 when 时间大小进行排序
    MessageQueue
    所以 handler.sendMessage 方法的作用是将消息加入到队列中。
    那么是在哪个位置处理消息呢?这里先带着疑问,先思考下面的问题。
    new Thread(new Runnable() {
       @Override
       public void run() {
           Handler handler1 = new Handler();
       }
    }).start();
    
    java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-3,5,main] that has not called Looper.prepare()
            at android.os.Handler.<init>(Handler.java:207)
            at android.os.Handler.<init>(Handler.java:119)
            at com.giraffe.school.MainActivity$2.run(MainActivity.java:47)
            at java.lang.Thread.run(Thread.java:919)
    
    为什么在子线程中实例化 Handler 会报错 ?跟着 Handler 源码看看
    public class Handler {
        ...
        public Handler() {
            this(null, false);
        }
        
        public Handler(@Nullable Callback callback, boolean async) {
            if (FIND_POTENTIAL_LEAKS) {
                final Class<? extends Handler> klass = getClass();
                if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                        (klass.getModifiers() & Modifier.STATIC) == 0) {
                    Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                        klass.getCanonicalName());
                }
            }
            
            mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                    "Can't create handler inside thread " + Thread.currentThread()
                            + " that has not called Looper.prepare()");
            }
            mQueue = mLooper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }
        ...
    }
    

    根据代码可以判断出 mLooper 是为 null 的,所以会抛出错误。

    Looper -> myLooper
    public final class Looper {
        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
        ...
        public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
        ...
    }
    
    sThreadLocal -> get
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
    

    get 方法的作用是通过 currentThread 获取一个 ThreadLocalMap 对象,然后以 sThreadLocal 为键来获取 Looper。

    为什么在主线程中实例 Handler 不会报错 ?跟着 ActivityThread 源码
    ActivityThread -> main
    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();
        ...
    }
    
    Looper -> prepareMainLooper
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    
    Looper -> prepare
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
    
    ThreadLocal -> set
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    

    set 方法的作用是通过 currentThread 获取一个 ThreadLocalMap 对象,然后将当前的 sThreadLocal 作为键,Looper 作为值存储起来,所以一个线程有且只有一个 Looper。

    prepare作用
    因为 ActivityThread 在 main 方法中已经调用了 prepare 方法,ThreadLocalMap 会设置一个(ThreadLocal,Looper) 的值,我们在 Activity 主线程中使用 Handler,通过当前主线程拿到 Looper,所以在主线程中使用 Handler 不会报错。
    子线程没有调用 prepare 方法,所以 ThreadLocalMap 会拿到一个 null 值,这就是导致抛出异常的原因。所以在子线程中使用 Handler 时,需要手动调用 Looper.prepare() 方法。
    ActivityThread -> main
    public static void main(String[] args) {
        ...
        Looper.loop();
        ...
    }
    
    Looper -> loop
    public static void loop() {
        final Looper me = myLooper();
        ...
        final MessageQueue queue = me.mQueue;
        for (;;) {
            Message msg = queue.next(); 
            ...
            msg.target.dispatchMessage(msg);
            ...
        }
        ...
    }
    

    loop 方法是获取当前线程的 Looper 对象,通过 Looper 对象获取到 MessageQueue,循环便利 Message,然后通过 Handler.dispatchMessage() 方法发送消息

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

    在分发消息时,会根据 msg.callback 来处理不同的方法。如果 msg.callback 不为 null,则调用 handleCallback() 方法。如果 msg.callback 为 null,则调用
    handleMessage() 方法。

    msg.callback 是什么?来到 Message 类中看看
    public final class Message implements Parcelable {
        ...
        @UnsupportedAppUsage
        /*package*/ Runnable callback;
    
        public static Message obtain(Handler h, Runnable callback) {
            Message m = obtain();
            m.target = h;
            m.callback = callback;
    
            return m;
        }
    
        @UnsupportedAppUsage
        public Message setCallback(Runnable r) {
            callback = r;
            return this;
        }
        ...
    }
    

    callback 是一个 Runnable,callback 赋值的地方有两个,一个是 obtain,一个是 setCallback

    Handler -> handleCallback
    private static void handleCallback(Message message) {
       message.callback.run();
    }
    
    Handler -> handleMessage
    public void handleMessage(@NonNull Message msg) {
    }
    

    所以如果设置了 Runnable ,那么会通过 handleCallback 调用 Runnable 的 run 方法。
    如果没有设置 Runnable,那么会调用 handleMessage 方法,让我们自己去处理。

    Handler 大致流程图
    Handler流程解析
    总结
    1. ActivityThread main 方法会调用 Loop.prepare() 方法,ThreadLocal 会设置一个 (mainThread,Looper) 的 ThreadLocalMap
    2. ActivityThread main 方法会调用 Loop.loop() 方法,Loop 会循环便利 MessageQueue,当 MessageQueue 不为空会通过 Handler.dispatchMessage 分发消息
    3. Handler.sendMessage 会将当前 Handler 绑定到 Message.target,并且将 Message 加入到 MessageQueue 中
    4. 这时候 MessageQueue 不为空,Loop 会通知 Handler.dispatchMessage。如果设置了 Runnable ,那么会通过 handleCallback 调用 Runnable 的 run 方法。
      如果没有设置 Runnable,那么会调用 handleMessage 方法,让我们自己去处理
    Handler 源码解析就介绍到这里了,如果有什么写得不对的,可以在下方评论留言,我会第一时间改正。

    相关文章

      网友评论

          本文标题:Android Handler 源码分析

          本文链接:https://www.haomeiwen.com/subject/tthooktx.html