1.简述
Handler消息机制主要包括:
MessageQueue
、Handler
、Looper、
Message
。Message:需要传递的消息,可以传递数据;
MessageQueue:消息队列,但是它的内部实现并不是用的队列,而是通过单链表的数据结构来维护消息列表,因为单链表在插入和删除上比较有优势。主要功能是向消息池投递消息(
MessageQueue.enqueueMessage
)和取走消息池的消息(MessageQueue.next
)。Handler:消息辅助类,主要功能是向消息池发送各种消息事件(
Handler.sendMessage
)和处理相应消息事件(Handler.handleMessage
);Looper:消息控制器,不断循环执行(
Looper.loop
),从MessageQueue中读取消息,按分发机制将消息分发给目标处理者。
2.异步线程切换原理
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Looper.prepare():创建Looper对象,放入到当前线程副本,Looper中创建MessageQueue对象,并让Looper对象持有当前线程,一个线程最多只有一个Looper对象否则会报错。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
// 规定了一个线程只有一个Looper,也就是一个线程只能调用一次Looper.prepare()
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per
thread");
}
// 如果当前线程没有Looper,那么就创建一个,存到sThreadLocal中
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
new Handler() :创建Handler对象,从当前线程副本中获取Looper对象,获取不到直接报错,获取到则持有Looper的MessageQueue.
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
Looper.loop():得到当前线程的Looper,从而得到当前线程的MessageQueue, 不断从当前线程的MessageQueue中取出Message,进行消息处理。
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
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.");
}
// 得到当前线程的MessageQueue
final MessageQueue queue = me.mQueue;
...
// 死循环
for (;;) {
// 不断从当前线程的MessageQueue中取出Message
Message msg = queue.next(); // might block
if (msg == null) {
//当MessageQueue没有元素时,方法阻塞
// No message indicates that the message queue is quitting.
return;
}
// Message.target是Handler,其实就是发送消息的Handler,这里就是调用它的dispatchMessage方法
msg.target.dispatchMessage(msg);
// 回收Message
msg.recycleUnchecked();
}
}
handlerMessage():我们一般会重写handlerMessage方法处理消息,这将会在msg.target.disPatchMessage方法中被回调。
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
handler.post():当我们在子线程中handler.post()发送消息的时候,即handler.sendMessage或者handler.post,首先会拼接Message对象,接着将从handler自身所在线程副本中获取到Looper的MessageQueue并向其中加入Message对象,即消息加入到消息队列,同时会将Message中的target赋值为handler自身,等当前Handler所在线程的Looper.loop()处理到该消息,即调用msg.target.disPatchMessage方法时,由于target就是Handler自身,disPatchMessage最终会回调Handler的handleMessage方法,这就实现了message从一个线程到另外一个线程的传递。
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
//组装消息
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
//发送消息 - 延时
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//发送消息 - 获取队列
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
//这里的MessageQueue就是取的Looper里面的
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) {
//this是Handler自身
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
3.总结
1.Handler 的背后有 Looper、MessageQueue 支撑,Looper 负责消息分发,MessageQueue 负责消息管理;
2.在创建 Handler 之前一定需要先创建 Looper,Looper 有退出的功能,但是主线程的 Looper 不允许退出;
3.异步线程Looper,Looper.prepare()创建Looper,Looper.loop()开始轮询,需要自己调用 Looper.myLooper().quit()
退出;
4.Runnable 被封装进了 Message,可以说是一个特殊的 Message;
5.Handler.handleMessage()
所在的线程是 Looper.loop() 方法被调用的线程;
6.Handler内存泄漏的原因
原因:MessageQueue持有Message,Message持有activity,delay多久,message就会持有activity多久。
解决方案:静态内部类、弱引用,最后不要忘记调用Handler.removeCallbacksAndMessages(null)清空所有消息。
原理:非静态的内部类和匿名类会隐式地持有一个他们外部类的引用,编译后内部类构造函数被定义为私有,构造函数参数为外部类的实例,所以它也是持有了外部类实例的引用,静态内部类不会持有外部类的引用。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
public class SampleActivity extends Activity {
/**
* Instances of static inner classes do not hold an implicit
* reference to their outer class.
*/
private static class MyHandler extends Handler {
private final WeakReference<SampleActivity> mActivity;
public MyHandler(SampleActivity activity) {
mActivity = new WeakReference<SampleActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
SampleActivity activity = mActivity.get();
if (activity != null) {
// ...
}
}
}
// MyHandler
private final MyHandler mHandler = new MyHandler(this);
/**
* Instances of anonymous classes do not hold an implicit
* reference to their outer class when they are "static".
*/
private static final Runnable sRunnable = new Runnable() {
@Override
public void run() { /* ... */ }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Post a message and delay its execution for 10 minutes.
mHandler.postDelayed(sRunnable, 1000 * 60 * 10);
// Go back to the previous Activity.
finish();
}
@Override
protected void onDestroy() {
super.onDestroy();
//mHandler.removeCallbacksAndMessages(null);
}
}