Handler处理机制
概念:
Handler是一种异步回调机制,也可以看作是线程之间的消息传递机制。对一些耗时操作放在另一个子线程中进行,子线程完成之后,将结果返回给主线程,主线程对其结果进行UI操作,即完成了主线程和子线程之间的线程信息传递。
涉及到的几个重要职责类:
Handler:负责消息Message的传递,分发以及处理等操作。
MessageQueue:消息队列,负责暂时缓存子线程发送过来的信息
Message:消息的封装类
Looper:循环从消息队列中拿出消息,交给handler进行处理
ThreadLocal:实现线程中的数据隔离性,每个线程中独有的数据可以放在这里面,避免其他线程修改。
Handler内部机制原理:
首先,正常情况下在主线程中对共享的Hander对象进行声明,然后主线程中进行实例化,并对其进行接受消息处理(重写方法)。开启子线程进行耗时操作,完成后进行数据传递
private Handler mHandler;
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//接受子线程传递过来的消息,在主线中进行逻辑处理
}
};
private void sendMessageToMainThreadByWorkThread() {
new Thread(){
@Override
public void run() {
//耗时操作
//从消息池中返回消息对象,避免消息的重复创建
Message message = mHandler.obtainMessage(MESSAGE_WHAT);
//将子线程的操作结果放入消息封装类中的Object对象中
message.obj = "I am message from work thread";
//handler对象将消息发送给消息队列中,供主线中进行取出。
mHandler.sendMessage(message);
}
}.start();
}
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
//==========================================================================
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//==========================================================================
public boolean sendMessageAtTime(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);
}
//==========================================================================
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//最终消息发送这个动作,还是在handler对象中调用消息队列的消息进队方法实现
return queue.enqueueMessage(msg, uptimeMillis);
}
还记得Looper类吗?之前说主线程是靠这个类从消息队列中进行循环取出消息,然后交给handler类进行消息处理,但是这边却没有看到looper的出现,这是为什么?
解释这个问题前,先理解一个东西:在handler机制中,上述方法的基本给出了从发送消息–》消息进入消息队列,底层过程。 但是取出消息,处理消息,是完全不一样的。任何线程从消息队列中取出消息都是依靠looper类的,looper类中的loop()实现了从消息队列中循环取出消息(后面介绍),因此如果一个线程想要从消息队列中获取消息,就必须要实现自己的Looper类,那么为什么主线程没有Looper类的实现?
通过底层代码,可以发现,原来主线程进行初始化的时候,就已经对Looper类自动实现.
ActivityThread类中,主方法:
public static void main(String[] args) {
//省略
Looper.prepareMainLooper();
//省略
Looper.loop();
//省略
}
可以发现主方法里面调用了Looper.prepareMainLooper();和Looper.loop();这个两个方法。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
//=======================================================
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));
}
//=======================================================
//对Looper类进行实例化时,会对消息队列也同时进行实例化
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
//====================================
public static @Nullable Looper myLooper() {
return sThreadLocal.get();//返回一个与主线程相关联的Looper对象
}
//---------------------------------------------------------------
//loop()函数,
public static void loop() {
//省略一堆系统的安全检查逻辑
//一个死循环,只有当消息队列没有任何消息对象时,才会退出。
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//循环取出消息的算法
}
}
通过上述两个方法可以知道,如果不是主线程进行消息的接收,那么需要在handlerMessage()方法之前,调用上述方法
private Handler handler;
private void handlerDemoByTwoWorkThread() {
Thread ThreadA = new Thread() {
@Override
public void run() {
Looper.prepare();//因为不是主函数,因此可以调用这个,创建Looper对象,同时和当前线程进行绑定
handler = new Handler() {//给出了handler实例,同时重写了处理消息的逻辑
@Override
public void handleMessage(Message msg) {
//逻辑处理
};
Looper.loop();//从消息队列中将消息循环取出。
}
};
这样的话基本了解了Message作为封装类、MessageQueue作为消息暂时存储的地方,ThreadLocal类存储每个线程自己的Looper对象引用,保证了每个线程拥有自己的取数据对象。
Handler机制的接发流程
Handler对象的具体流程,
发送消息的处理流程基本没啥可说的,就是通过共享的handler对象,调用其中的obtainMessage()方法,从消息队列中获取消息封装对象,然后将结果存储在消息封装对象的对应属性中,最后通过调用sendMessage(Message msg)方法进行消息的传递。底层实现上面有介绍。
着重记录以下线程如何从消息队列中拿出消息:
Looper的创建,绑定。以及loop()方法循环拿数据,前面提过一下,这里看一下loop()函数,取数据的逻辑操作,取出数据后如何将数据给到handler对象中,进行内容的处理。
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;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//循环取出的算法
try {
//调用消息本体的target属性中的dispatchMessage(msg)方法来进行消息的处理
msg.target.dispatchMessage(msg);
//.............
} finally {
//.............
}
//.......
}
}
loop()方法取出消息之后,会调用该方法的target属性,
/*package*/ Handler target;
通过查看消息封装类中的代码,可以看到target是一个handler对象的声明。也就是意味着,每一个产生的消息都可以指定不动的handler来进行处理,这就是为什么一个线程可以有多个handler(一个线程可以产生很多的消息,通过指定,可以为每个消息实体绑定不同的handler处理对象。)
总结:loop()方法取到了消息,通过该消息的target属性,获得对应的handler处理对象,调用handler对象的dispatchMessage(msg)方法,将消息进行分发,具体处理逻辑:先看消息本身是否有回调方法,如果没有看handler是否有回调方法,如果上述都没有,则会调用handler本身的handleMessage方法。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//如果,通过obtainMessage获得的Message对象,进行了setcallback(Runnable r)的话,会调用消息自身的回调方法进行处理。----》消息对象自己实现回调后的逻辑处理
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
//如果实例化Handler的时候,传递了Callback对象的话,那么回调会调用callback中所实现的handleMessage(msg)方法,
return;
}
}
//调用子类重写的handleMessage(msg)方法,如果子类不重写的话,是一个无实现体的方法
handleMessage(msg);
}
}
存取的流程图
最后补充:
消息的创建,使用了消息池,
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();
}
在创建消息时会先从消息池中去查询是否有消息对象,如果有,则直接使用消息池中的对象,如果没有,则创建一个新的消息对象。
使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
//==========================
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();//如果创建其他的Hander对象的话,其他handler对象的获取数据也是通过当前线程的唯一Looper线程来操作的
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;
}