Handler机制(Looper、Message、MessageQueue)源码追踪
介绍
本文是自己看Handler源码的一个流程,主要对主线进行了追踪查看。
如有写的不正确或者分析不正确的,麻烦大佬指出。跪谢啦!
Handler机制涉及主要相关类
- Handler
发消息、处理消息
- Looper
轮询消息队列,一个线程只有一个Looper
- Message
消息的存储对像
- MessageQueue
消息列表(消息不会直接添加到MessageQueue中,
而是通过与Looper关联的{@link Handler}对象)
先抛出几个问题:
- Looper什么时候创建的?
- MessageQueue什么时候创建的?
- Looper和当前线程是什么时候绑定的?
- Message和Handler什么时候绑定的?
- Message什么时候放入MessageQueue?
源码追踪
new Handler();
先从new 一个Handler看起:
点进去,看到Handler构造方法里调用了
mLooper = Looper.myLooper();
public Handler(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();// 这里获取一个Looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
关键方法: Looper.myLooper()
myLooper();点进去发现是sThreadLocal.get()直接获取的。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
而sThreadLocal是一个用来存储Looper的本地变量
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
我们再去查看sThreadLocal 哪里调用了。发现只有三个地方调用了,有一个调用的方法是直接设置Looper的:
sThreadLocal.set(new Looper(quitAllowed)); 发现这里直接是new Looper。
关键方法:sThreadLocal.set(new Looper(quitAllowed));
继续追踪,发现sThreadLocal.set(new Looper(quitAllowed)); 是在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));
}
到这里我们发现了这是Looper的创建时间!
好奇宝宝肯定点击进去看下的:new Looper();我们点击看下
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
// 是不是发现了什么,MessageQueue在Looper的构造方法里创建的,同时Looper和线程也绑定了
总结: Looper的创建时间,也是MessageQueue创建的时间,同时 也是Looper和线程绑定的时间。
关键方法:prepare
继续追踪,谁又调用了prepare呢
prepare();
public static void prepare() { // 消息队列可以quit
prepare(true);
}
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));
}
继续追踪,发现 Looper.class 的107行调用的prepare(false);
public static void prepareMainLooper() {
prepare(false); // 这里调用的prepare。//消息队列不可以quit
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
再继续追踪prepareMainLooper ,我们会追踪到ActivityThread这个类里面。
prepareMainLooper()
主线程就是UI线程,Activity由ActivityThread启动,会调用ActivityThread的main函数:
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// 省略N行代码................
Looper.prepareMainLooper(); // 看到这里我们就明白了,
ActivityThread thread = new ActivityThread();
thread.attach(false);
// 省略N行代码................
Looper.loop();// 开始轮询
throw new RuntimeException("Main thread loop unexpectedly exited");
}
我们从使用Handler处追踪,到这里我们是往上层追踪到ActivityThread的**main(String[]args)**方法里。
这就证明了Looper的创建时间,Activity启动时就会为ui线程创建一个Looper。Looper构造方法里进行MessageQueue的创建、Looper和线程的绑定。**
关键方法流程:
new Handler() ---->
Looper.myLooper() ---->
sThreadLocal.set(new Looper(quitAllowed)) ---->
prepare(boolean quitAllowed) ---->
prepareMainLooper()---->
ActivityThread的main(String[] args)
附上流程图:
Message的创建、以及与Handler的绑定
消息创建
Message obtain = Message.obtain();也可以直接new Message ();使用obtain很更好点,看下方源码上的注释:
//obtain 源码中有很多这个方法,这里只拷贝出这两个
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
* 从全局池返回一个新的消息实例。让我们
*在很多情况下避免分配新对象
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
//这里也可以直接绑定Handler,即使不绑定Handler中enqueueMessage也会去绑定的
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
Message与Handler的绑定、Message放入MessageQueue
handler发送消息的几个方法:
- sendEmptyMessage()
- sendEmptyMessageAtTime()
- sendEmptyMessageDelayed()
- sendMessageAtFrontOfQueue();
- sendMessage()
- sendMessageAtTime()
- sendMessageDelayed
我们换个方向从这里作为入口去追踪 Message与Handler的绑定:
点击去一直往下追踪,会发现调用哪个最终都会调用enqueueMessage();(post(); (post开头的几个函数也是一样)):
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; // 这里是Handler与Message的绑定
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis); //最终消息都会放入MessageQueue
}
Handler处理消息
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//我们从handleMessage点击去继续追踪
}
};
消息最终由Looper取出,交给Handler的dispatchMessage进行处理
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) { //进行消息分发
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
还记得 会调用ActivityThread的main函数吗?调用了 Looper.loop();
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// 省略N行代码................
Looper.prepareMainLooper(); // 看到这里我们就明白了,
ActivityThread thread = new ActivityThread();
thread.attach(false);
// 省略N行代码................
Looper.loop();// 开始轮询
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper.loop();
最终由Looper取出消息进行消息分发。
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
/// 省略N行代码...........
for (;;) {
Message msg = queue.next(); // might block
/// 省略N行代码...........
try {
msg.target.dispatchMessage(msg); // 这里调用了Handler的dispatchMessage进行消息分发
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
/// 省略N行代码...........
}
}
附上消息分发流程图:
补充
handler发消息给子线程(子线程可不可以new Handler()),looper怎么启动?
场景:Handler的创建不是在主线程创建的,是在子线程创建的
public class MainActivity extends AppCompatActivity {
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new MyRunnable()).start();
findViewById(R.id.send_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message msg = Message.obtain();
msg.what = SEND_MESSAGE;
msg.obj = "主线程向子线程发送新的消息啦";
mHandler.sendMessage(msg);
}
});
}
private class MyRunnable implements Runnable {
@Override
public void run() {
//建立消息循环的步骤
Looper.prepare();//1、初始化Looper
mHandler = new Handler() {// 2、绑定handler到CustomThread实例的Looper对象
public void handleMessage(Message msg) {
//4.处理消息
}
};
Looper.loop();//3、启动消息循环
}
}
}
- 首先通过 Looper.prepare() 初始化Looper
- new Handler();创建Handler就是绑定当前Thread实例的Looper对像
- Looper.loop(); 启动消息循环
- 最后handleMessage就可以正常接收消息了
注:在子线程new Handler();需要先去初始化Looper,还要去开启Looper.loop()。如上所示
注:如有什么不对,理解不到位的麻烦各位看官指出!在下感激不尽。