我们可以使用一个Handler发送并处理一个线程关联的Message或者Runnable。(注意:Runnable也会被封装到Message.Callback)
基本用法
//自定义Handler创建
static class MHandler extends Handler {
@Override
public void handleMessage(Message msg) {
//消息处理
super.handleMessage(msg);
}
}
//消息发送
mHandler.sendMessage(Message.obtain());
mHandler.post(Runnable);
实际上在我们实例化Handler之前,都会先检查当前线程的Looper是否存在,如果不存在则会抛出异常。也就是说在我们创建Handler之前一定要先调用Looper.prepare()
实例化Handler代码如下:
public Handler(Callback callback, boolean async) {
//获取当前线程Looper,从线程的ThreadLocal中获取
mLooper = Looper.myLooper();
//如果当前线程不存在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;
}
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));
}
Looper提供prepare方法用来实例化Looper,借助ThreadLocal来实现和当前线程的绑定,Looper.loop()开始轮训消息队列,获取消息并调用Message.target 进行处理
Handler提供了一些方法进行发送消息,包括sendMessage和post。
最终会调用Handler的MessageQueue.enqueueMessage()进行入队操作
MessageQueue的底层实现是单链表
Handler sendEmptyMessage(int)
-> sendEmptyMessageDelayed(int, int)
-> sendMessageAtTime(Message, long)
-> enqueueMessage(MessageQueue, Message, long)
-> queue.enqueueMessage(Message, long);
Looper.loop()是一个死循环,负责从消息队列中取出消息,交给Handler进行处理
//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;
//...
for (;;) {
// 不断从 MessageQueue 获取 消息
Message msg = queue.next(); // might block
//退出 Looper
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//...
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
//...
}
//消息回收,放在Message的静态变量,消息池里面,进行消息重用,减少对象的创建开销
msg.recycleUnchecked();
}
}
Loop()方法调用MessageQueue.next()方法取出消息
//MessageQueue
Message next() {
//...
for (;;) {
//...
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//...
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
}
// Run the idle handlers. 关于 IdleHandler 自行了解
//...
}
}
loop()从消息队列取出消息之后,调用msg.target.dispatchMessage() msg.target就是Handler
//Handler
public void dispatchMessage(Message msg) {
//msg.callback 是 Runnable ,如果是 post方法则会走这个 if
if (msg.callback != null) {
//如果是Handler.post(runnable)发送的消息,不会进入handleMessage方法
handleCallback(msg);
} else {
//callback 见【3.4】
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//回调到 Handler 的 handleMessage 方法
handleMessage(msg);
}
}
Handler允许我们发送延时消息,延时期间用户关闭Activity就会产生内存泄漏
这个泄漏是因为Handler持有Activity的引用,这是因为内存类持有外部类的引用,解决这个问题的办法就是将Handler定义成静态内部类
private static class SafeHandler extends Handler {
private WeakReference<HandlerActivity> ref;
public SafeHandler(HandlerActivity activity) {
this.ref = new WeakReference(activity);
}
@Override
public void handleMessage(final Message msg) {
HandlerActivity activity = ref.get();
if (activity != null) {
activity.handleMessage(msg);
}
}
}
并且在Activity.onDestroy()移除消息,加一层保障
@Override
protected void onDestroy() {
safeHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
前面我们提到,在使用Handler之前必须先实例化Looper,主线程当然也不例外。
因为在应用程序启动的时候,也就是ActivityThread main()方法里面已经进行了初始化操作
//android.app.ActivityThread
public static void main(String[] args) {
//初始化主线程Looper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
//主线程循环,如果循环退出,则应用程序也就退出了
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
public void dispatchMessage(Message msg) {
//这里的 callback 是 Runnable
if (msg.callback != null) {
handleCallback(msg);
} else {
//如果 callback 处理了该 msg 并且返回 true, 就不会再回调 handleMessage
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Handler.Callback 有优先处理消息的权利,我们可以通过Callback机制进行消息拦截
public static boolean isMainThread() {
return Looper.myLooper() == Looper.getMainLooper();
}
Android中为什么主线程不会卡死
个人理解:
主线程的所有操作都是通过ActivityThread.H进行分发的,包括Activity Service BroadcastReceiver 屏幕点击事件等
我们所说的主线程阻塞其实就是在主线程进行耗时操作,产生ANR,主线程的操作其实就是一个message,如果这个message是耗时操作,阻塞的是loop()方法,导致其他消息无法正常处理,所以会阻塞。loop()方法保证主线程一直存活。
Looper可以比喻成一个传送带,Message比喻成一个物品,传送带将一个物品运送到端就是Handler处理消息的过程,处理完就开始处理下一个消息。