美文网首页
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