第一次在掘金上发表文章,生怕说错了什么误人子弟,更不敢标题党。
若是文章有误,欢迎您直接在评论指出。java
Handler 与 Message、MessageQueue、Looper 一块儿构成了 Android 的消息机制,Android 系统经过大量的消息来与用户进行交互,View 的绘制、点击事件、Activity 的生命周期回调等都做为消息由主线程的 Handler 来处理。android
Handler 在消息机制中的做用是:发送和处理消息。git
Handler 还有另外一个重要的做用,跨线程通讯。最多见的就是子线程请求网络,而后使用 Handler 将请求到的数据 post 到主线程刷新 UI,大名鼎鼎的 Retrofit 也是这么作的。网络
建立 Handler 并发
private Handler handler = new Handler() {
// 重写 handleMessage 来根据不一样 what 来处理 Message
// 这个方法在 Handler 建立的线程执行
@Override public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
MLog.i(msg.obj);
break;
case 1:
break;
default:
}
}
};复制代码
建立并发送 Message异步
// 获取一个 Message
Message message = Message.obtain();
message.what = 0;
message.obj = new Object();
// 使用 Handler 发送 Message
// 消息发送完成后 Handler 的 handleMessage(Message msg) 会处理消息
handler.sendMessage(message);
// 延迟 1s 发送 Message
handler.sendMessageDelayed(message, 1000);
// 发送一个空的 Message
handler.sendEmptyMessage(msg.what);
// 延迟发送一个空的 Message
handler.sendEmptyMessageDelayed(0, 1000);
// 还能够这样
// 建立 Message 并绑定 Handler
Message message = handler.obtainMessage();
message.what = 0;
message.obj = new Object();
// 发送 Message
message.sendToTarget();复制代码
使用 Handler 子线程请求数据,主线程刷新 UIasync
// 1. 在主线程建立 Handler(略)
// 2. 子线程请求数据,主线程刷新 UI
new Thread(new Runnable() {
@Override public void run() {
// 获取网络数据
final List<Object> datas = getNetData();
// 方法一:将数据做为 Message 的 obj 发送出去,在 handleMessage 中刷新 UI
Message msg = Message.obtain();
msg.what = 1;
msg.obj = data;
handler.sendMessage(msg);
// 方法二:直接在 post 中刷新 UI
handler.post(new Runnable() {
@Override public void run() {
// 使用 datas 刷新 UI
// 这个方法也会在 Handler 建立的线程执行
}
});
}
}).start();复制代码
不得不说,上面使用 Handler 的方法会有内存泄漏的风险ide
Handler 内存泄漏的两个缘由函数
Java 中非静态内部类和匿名内部类会持有外部类的引用oop
// 这是一个外部类 Handler 不会持有外部类引用
// 显然 handleMessage 没地方写了
Handler handler = new Handler();
// 重写 handleMessage 后将获得一个内部类 Handler,之内 handleMessage 是在外部类中实现的
// 它持有外部类引用,可能会引发内存泄漏
Handler handler = new Handler() {
@Override public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
MLog.i(msg.obj);
break;
case 1:
break;
default:
}
}
};
// 这里 Handler 是一个匿名类,但不是内部类
// Runnable 是一个匿名内部类,持有外部类引用,可能会引发内存泄漏
new Handler().post(new Runnable() {
@Override public void run() {
// ...
}
});复制代码
Handler 的生命周期比外部类长。
分析
解决方案:
代码
// Handler 弱引用封装
public class SafetyHandler<T> extends Handler {
/** * 外部引用, 例如 Activity, Fragment, Dialog, View 等 */
private WeakReference<T> mTargetRef;
public SafetyHandler() {
}
public SafetyHandler(T target) {
this.mTargetRef = new WeakReference<>(target);
}
public T getTarget() {
if (isTargetAlive()) {
return mTargetRef.get();
} else {
removeCallbacksAndMessages(null);
return null;
}
}
public void setTarget(T target) {
this.mTargetRef = new WeakReference<>(target);
}
private boolean isTargetAlive() {
return mTargetRef != null && mTargetRef.get() != null;
}
}
// 在 Fragment 中使用方法
// 想重写 handleMessage 的话,要建立静态内部类或者外部类,不然有内存泄漏风险
private static class MyHandler extends SafetyHandler<MyFragment> {
MyHandler(MyFragment fragment) {
super(fragment);
}
@Override public void handleMessage(Message msg) {
super.handleMessage(msg);
if(getTarget() != null) {
MyFragment fragment = getTarget();
switch (msg.what) {
// 操做 fragment
}
}
}
}
// 声明 Handler
MyHandler handler = new MyHandler(this);
// 使用 Handler
handler.sendMessage() ...
// onDestroy
@Override public void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
}复制代码
这部分从 ActivityThread 的 main 方法出发,打通整个消息机制的流程,结合源码体验效果更佳。
介绍消息机制的原理前,咱们先来看一下 Handler 与 Message、MessageQueue、Looper 这个四个类的做用
注意:每一个线程只能有一个 Looper 和 一个 MessageQueue,能够有多个 Handler,每一个 Handler 能够发送和处理多个 Message。
另外,提到消息机制就不得不说一下 Android 中的主线程(UI 线程)
Android 中的主线程经过 Looper.loop() 进入一个无线循环中,不断的从一个 MessageQueue 取出消息,处理消息,咱们每触发一个事件,就会向这个 MessageQueue 中添加一个消息,Looper 取出这个消息,Handler 处理这个消息,正是 Looper.loop() 在驱动着 Android 应用运行下去 ,这也是为何 Looper.loop 为何不会阻塞住主线程的缘由(固然前提是在 ActivityThread 的 main 函数 中调用)。
本源码分析基于 API 25,如下源码中删除了一些无关的代码
一、在主线程的入口,ActivityThread 的 main 方法
public static void main(String[] args) {
// 准备主线程的 Looer
Looper.prepareMainLooper();
// 建立 ActivityThread
ActivityThread thread = new ActivityThread();
thread.attach(false);
// 获取主线程的 Handler
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// 对消息队列进行无线轮询,处理消息
Looper.loop();
// 一旦跳出循环,抛出异常(Android 不容许跳出主线程的 Looper.loop())
throw new RuntimeException("Main thread loop unexpectedly exited");
}复制代码
-> Looper.prepareMainLooper()
public static void prepareMainLooper() {
// 准备一个 Looper
prepare(false);
synchronized (Looper.class) {
// main Looper 只能初始化一次,再次初始化会抛出异常
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
// 获取 main Looper
sMainLooper = myLooper();
}
}复制代码
-> prepare(false)
// 准备一个 Looper,quitAllowed 是否容许 Looper 中的 MessageQueue 退出
// 默认 prepare() 容许退出,主线程这里不容许退出
private static void prepare(boolean quitAllowed) {
// 先看下 sThreadLocal 是什么
// static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
// ThreadLocal:线程本地存储区,每一个线程都有本地存储区域,这个区域是每一个线程私有的,不一样的线程不能之间不能彼此访问
// 若是 sThreadLocal 中有数据,抛出异常,换句话说 prepare() 这个函数每一个线程只能执行一次
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 建立 Looper 保存到该线程的 ThreadLocal 中
sThreadLocal.set(new Looper(quitAllowed));
}复制代码
-> new Looper(quitAllowed)
private Looper(boolean quitAllowed) {
// 在 Looper 建立的时候建立一个消息队列
// quitAllowed:消息队列是否能够退出,主线的消息队列确定不容许退出,因此上面是 prepare(false)
// quitAllowed 为 false 执行 MessageQueue#quit 退出消息队列时会出现异常
mQueue = new MessageQueue(quitAllowed);
// 获取 Looper 存在于哪一个线程
mThread = Thread.currentThread();
}复制代码
-> sMainLooper = myLooper()
public static @Nullable Looper myLooper() {
// 从 sThreadLocal 中获取当前线程的 Looper
// 若是当前线程没有掉用 Looper.prepare 返回 null
return sThreadLocal.get();
}复制代码
-> sMainThreadHandler = thread.getHandler();
final Handler getHandler() {
// 返回 mH
return mH;
}
// mH 在成员变量的位置 new H()
final H mH = new H();
// H 继承了 Handler 封装了一系列关于 Acitivty、Service 以及其余 Android 相关的操做
private class H extends Handler复制代码
总结:在主线程的 main 方法中,会建立主线程的 Looper、MessageQueue,而后进入 Looper.loop() 循环中,不断的取出消息,处理消息,以此来驱动 Android 应用的运行。
二、Handler 的建立,Handler 的全部构造方法都会跳转到下面两个之一
public Handler(Callback callback, boolean async) {
// Hanlder 是匿名类、内部类、本地类时,若是没有声明为 static 则会出现内存泄漏的警告
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());
}
}
// 获取 Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
}
// 消息队列,从 Looper 中获取
mQueue = mLooper.mQueue;
// 处理消息的回调接口
mCallback = callback;
// 处理消息的方式是否为异步,默认同步
mAsynchronous = async;
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}复制代码
总结:在 Handler 的构造方法中,Handler 和 Looper、MessageQueue 绑定起来,若是当前线程没有 Looper 抛出异常(这也是为何直接在子线程建立 Handler 会出现异常)。
三、使用 Handler 发送消息
-> sendMessageAtTime(Message msg, long uptimeMillis)
// 除了 sendMessageAtFrontOfQueue,Handler 全部的 post、sendMessage 都会跳到这个方法
// Message msg: 要发送的消息
// long uptimeMillis: 发送消息的绝对时间,经过 SystemClock.uptimeMillis() 加上咱们本身的延迟时间 delayMillis 计算而来
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
// 消息队列为空(可能已经退出)返回 false 入队失败
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);
}复制代码
-> sendMessageAtFrontOfQueue(Message msg)
// 发送消息到 MessageQueeu 的队头
public final boolean sendMessageAtFrontOfQueue(Message msg) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
// 经过设置 uptimeMillis 为 0,是消息加入到 MessageQueue 的队头
return enqueueMessage(queue, msg, 0);
}复制代码
-> enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
// 全部 Handler 的 post 、sendMessage 系列方法和 runOnUiThread 最终都会调用这个方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// msg.target 是一个 Handler,将 Message 和 Handler 绑定
// 也就是用哪一个 Handler 发送消息,这个 Message 就和哪一个 Handler 绑定
msg.target = this;
// 若是设置了消息处理方式为异步处理
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// MessageQueue 的方法,将消息入队
return queue.enqueueMessage(msg, uptimeMillis);
}复制代码
-> MessageQueue#enqueueMessage(Message msg, long when)
boolean enqueueMessage(Message msg, long when) {
// Messgae 没有绑定 Handler 抛出异常
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
// Messgae 正在使用 抛出异常
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
// 消息队列正在退出,回收 Message
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(); // 调用 Message#recycleUnchecked()
return false;
}
msg.markInUse(); // 标记 Message 正在使用
msg.when = when; // 设置 Message 的触发时间
// mMessages 记录着 MessageQueue 的队头的消息
Message p = mMessages;
boolean needWake;
// MessageQueue 没有消息、Message 触发时间为 0、Messgae 触发时间比队头 Message 早
// 总之这个 Message 在 MessageQueue 中须要最早被分发
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p; // 将之前的队头 Message 连接在这个 Message 后面
mMessages = msg; // 将这个 Message 赋值给 mMessages
needWake = mBlocked; // 队列是否阻塞
} else {
// 标记队列是否阻塞
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// 按照时间顺序将 Message 插入消息队列
for (;;) {
prev = p; // prev 记录队头
p = p.next; // p 记录队头的后一个
// 队头后面没有消息或者其触发事件比要插入的 Message 晚,跳出循环
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
// 将 Message 插入队列
msg.next = p;
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}复制代码
总结:到如今为止,咱们的 Handler 已经将 Message 发送到了 MessageQueue,Message 静静的等待被处理。
四、Looper.loop() 还记得这个方法在 ActivityThread 的 main 调用了吗?正是它在不断处理 MessageQueue 里面的消息。
public static void loop() {
// 获取 Looper.Looper.prepare 准备好的 Looper
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 获取 Looper 中的消息队列
final MessageQueue queue = me.mQueue;
// 进入无线循环
for (;;) {
// 取出下一条消息
Message msg = queue.next();
// 没有消息,退出 loop
// 其实上面 queue.next() 也是一个无限循环,获取到消息就返回,没有消息就一直循环
if (msg == null) {
return;
}
try {
// msg.target 实际上就是一个 Handler
// 获取到了消息,使用绑定的 Handler#dispatchMessage 分发消息
msg.target.dispatchMessage(msg);
} finally {
}
// 释放消息,把 Message 的各个变量清空而后放进消息池中
msg.recycleUnchecked();
}
}复制代码
五、Handler#dispatchMessage(msg) 消息是如何处理的
public void dispatchMessage(Message msg) {
// 1
if (msg.callback != null) {
handleCallback(msg);
} else {
// 2
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 3. 看到这个方法没有!就是咱们建立 Handler 时重写的 handleMessage
// OK 整个流程打通!
handleMessage(msg);
}
}复制代码
总结:流程虽然通了,可是处理 Message 的方法貌似有三种(我标记了序号),并且咱们的 handleMessage 的优先级最低,其余方法会在什么状况下执行呢? 直接说结论了,调用 Handler 的 post 系列方法会走序号1的处理,建立 Handler 传入 Callback 会走序号2 的处理。
Handler 机制总结:想使用 Handler 必需要有 Looper,建立 Looper 的时候会建立 MessageQueue,在 Handler 的构造的时候会绑定这个 Looper 和 MessageQueue,Handler 将 Message 发送到 MessageQueue 中,Looper.loop() 会不断的从 MessageQueue 取出消息再交给这个 Handler 处理。
new Thread(new Runnable() {
@Override public void run() {
new Handler().post(new Runnable() {
@Override public void run() {
MLog.i("Handler in " + Thread.currentThread().getName());
}
});
}
}).start();复制代码
答案前面提到了是不能,执行上面的代码会出现 java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 这个异常,异常提示咱们,不能再没有调用 Looper.prepare() 的线程中建立 Handler。
简单修改下代码就能够了,给线程准备好 Looper
new Thread(new Runnable() {
@Override public void run() {
// 准备一个 Looper,Looper 建立时对应的 MessageQueue 也会被建立
Looper.prepare();
// 建立 Handler 并 post 一个 Message 到 MessageQueue
new Handler().post(new Runnable() {
@Override public void run() {
MLog.i("Handler in " + Thread.currentThread().getName());
}
});
// Looper 开始不断的从 MessageQueue 取出消息并再次交给 Handler 执行
// 此时 Lopper 进入到一个无限循环中,后面的代码都不会被执行
Looper.loop();
}
}).start();复制代码
// 1. 建立 HandlerThread
handlerThread = new HandlerThread("myHandlerThread") {
// onLooperPrepared 这个方法子线程执行,由线程的 run 方法调用,能够在里面直接建立 Handler
@Override protected void onLooperPrepared() {
super.onLooperPrepared();
new Handler().post(new Runnable() {
@Override public void run() {
// 注意:Handler 在子线程建立,这个方法也会运行在子线程,不能够更新 UI
MLog.i("Handler in " + Thread.currentThread().getName());
}
});
}
};
// 2. 准备 HandlerThread 的 Looper 并调用 onLooperPrepared
handlerThread.start();
// 3. 退出
@Override public void onDestroy() {
super.onDestroy();
handlerThread.quit();
}
// 也能够这样用
// 1. 建立 HandlerThread 并准备 Looper
handlerThread = new HandlerThread("myHandlerThread");
handlerThread.start();
// 2. 建立 Handler 并绑定 handlerThread 的 Looper
new Handler(handlerThread.getLooper()).post(new Runnable() {
@Override public void run() {
// 注意:Handler 绑定了子线程的 Looper,这个方法也会运行在子线程,不能够更新 UI
MLog.i("Handler in " + Thread.currentThread().getName());
}
});
// 3. 退出
@Override public void onDestroy() {
super.onDestroy();
handlerThread.quit();
}复制代码
HandlerThread 继承了 Thread,本质是一个拥有 Looper 的线程,所以在 HandlerThread 咱们能够直接使用 Handler。
构造方法
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
// 传入线程的名称和优先级
// 注意 priority 的值必须来自 android.os.Process 不能来自 java.lang.Thread
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}复制代码
run 方法:建立子线程的 Looper
@Override
public void run() {
mTid = Process.myTid();
// 准备一个 Looper
Looper.prepare();
synchronized (this) {
// 获取 Looper
mLooper = Looper.myLooper();
// Looper 获取成功后,唤醒 getLooper 的 wait
notifyAll();
}
Process.setThreadPriority(mPriority);
// Looper 准备好的回调,在这个方法里可使用 Handler 了
onLooperPrepared();
// Looper 开始循环取消息
Looper.loop();
mTid = -1;
}复制代码
getLooper 方法:获取子线程的 Looper
public Looper getLooper() {
// 线程没有开始或者死亡,返回 null
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
// Looper 的建立时在子线程完成的,而 getLooper 可能会在主线程调用
// 当 Looper 没有建立完成时,使用 wait 阻塞等待
// 上面在 Looper 建立好后会 notifyAll 来唤醒 wait
synchronized(this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}复制代码
quit 和 quitSafely :结束 Looper 的运行
// quit
quit() -> looper.quit() -> mQueue.quit(false);
// quitSafely
quitSafely() -> looper.quitSafely() -> mQueue.quit(true);
// 这两个方法最终都会调用到 MessageQueue 的 void quit(boolean safe) 方法
// 前者会直接移除 MessageQueue 中的全部消息,而后终止 MessageQueue
// 后者会将 MessageQueue 中已有消息处理完成后(再也不接收新消息)终止 MessageQueue复制代码