Handler
因为 Android 只允许在主线程更新 UI ,所以我们在子线程获取到的数据需要切换线程到主线程再做 UI 处理,而 Handler 是一种用于线程间消息传递的机制,能够实现线程切换的功能。
基本使用方式
步骤一: 创建 Handler 实例
// callback 方式
private Handler callbackHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// 更新UI等操作
return true;
}
});
// 成员内部类
private Handler innerHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 更新UI等操作
}
};
// 静态自定义 Handler 内部类
private static class MyHandler extends Handler {
private WeakReference<MainActivity> mReference;
public MyHandler(MainActivity activity) {
mReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
// 更新UI等操作
if (mReference.get() != null) {
switch (msg.what) {
case 0:
Toast.makeText(mReference.get(), msg.obj.toString(), Toast.LENGTH_SHORT).show();
break;
case 1:
Toast.makeText(mReference.get(), "这是空消息方式", Toast.LENGTH_SHORT).show();
break;
case 2:
Toast.makeText(mReference.get(), "这是延时空消息方式", Toast.LENGTH_SHORT).show();
break;
}
}
}
}
总结:通常使用自定义静态内部类的方式来使用,能够避免内存泄漏。
步骤二: 调用 Handler 相关send 或 post 方法
// 子线程中发送消息
new Thread(new Runnable() {
@Override
public void run() {
Message message = Message.obtain();
message.what = 0;
message.arg1 = 100;
message.obj = "普通消息方式";
// send 方式发送普通消息和延时消息
mMyHandler.sendMessage(message);
mMyHandler.sendMessageDelayed(message, 2000);
// 发送空消息
mMyHandler.sendEmptyMessage(1);
mMyHandler.sendEmptyMessageDelayed(2, 5000);
// post 方式发送普通消息
mMyHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "Runnable 消息方式", Toast.LENGTH_SHORT).show();
}
});
// post 方式发送延时消息
mMyHandler.postDelayed(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "Runnable 延时消息方式", Toast.LENGTH_SHORT).show();
}
}, 1000);
}
}).start();
步骤三: 移除相关消息
这一步不是必须的,是为了确保避免内存泄露风险。
@Override
protected void onDestroy() {
super.onDestroy();
mMyHandler.removeCallbacksAndMessages(null);
}
总结: 通常发送消息的方式有 3 种,分别是 sendMessage 、 sendEmptyMessage 、post 方法,每种方式又有延时发送的方法,分别是 sendMessageDelayed 、 sendEmptyMessageDelayed 、 postDelayed,延时发送的时间单位为毫秒,即多少毫秒后再发送。
源码分析
以下相关源码会省略一些跟分析无关的代码,只保留关键代码。
ActivityThread
在应用线程的入口类 ActivityThread 的 main 方法中,有如下调用:
public static void main(String[] args) {
// 创建主线程 Looper
Looper.prepareMainLooper();
// Looper 开始工作
Looper.loop();
}
在 mian 方法中,调用了跟 Looper 相关的两个方法,接下来我们看一下 Looper 类。
Looper
先看一下 Looper 类重要的成员变量
public final class Looper {
// ThreadLocal 绑定线程和 Looper 对象
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
// 主线程的 Looper 对象
private static Looper sMainLooper;
// 消息队列
final MessageQueue mQueue;
// 当前线程
final Thread mThread;
}
我们先看 prepareMainLooper 相关方法:
public static void prepareMainLooper() {
// false 表示不允许退出
prepare(false);
synchronized (Looper.class) {
// 这里判断 Looper 是否已经存在了,只允许有一个
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
// 该方法主要给子线程调用
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
// 这里判断 Looper 只允许有一个,方法只能调用一次
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 初始化 Looper 对象并放进 ThreadLocal 里面
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
// 创建消息队列
mQueue = new MessageQueue(quitAllowed);
// 初始化当前线程 ,线程关联从这里开始
mThread = Thread.currentThread();
}
prepareMainLooper() 方法内容归纳:
判断
Looper是否已经存在,存在则报异常。初始化
Looper对象并放进ThreadLocal里面。Looper里面初始化了MessageQueue对象并初始化了当前线程。
现在,我们看一下 loop() 方法,:
public static void loop() {
// 从 ThreadLocal 中获取当前线程的 Loop
final Looper me = myLooper();
// 如果 Looper 还没初始化,则报错
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(); // might block
if (msg == null) {
// 消息为空 ,结束循环
return;
}
try {
// 回调 Handler 的 dispatchMessage 方法
msg.target.dispatchMessage(msg);
} finally {
}
// 对分发了的消息进行回收操作
msg.recycleUnchecked();
}
}
loop() 方法里面的逻辑归纳为:
先判断
Looper对象是否已经初始化。在死循环里面不断调用
Looper的成员MessageQueue的next()方法来获取Message对象。取出的消息不为空则回调
Message对象的成员target的dispatchMessage方法 (tartget其实就是Handler)。对分发了的消息进行回收操作。
Handler
Looper 中会回调 Handler 的 dispatchMessage 方法,那么我们先看一下 Handler 类重要的成员变量和方法:
public class Handler {
// 当前线程对应的 Looper
final Looper mLooper;
// 指向 Looper 的 MessageQueue
final MessageQueue mQueue;
// Callback 对象
final Callback mCallback;
// 是否是异步消息,默认同步
final boolean mAsynchronous;
// Callback 接口对象
public interface Callback {
public boolean handleMessage(Message msg);
}
// 该方法需要子类覆写实现逻辑操作
public void handleMessage(Message msg) {
}
}
构造方法
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(boolean async) {
this(null, async);
}
public Handler(Callback callback, boolean async) { //该构造给主线程调用
// 指向 Looper 对象
mLooper = Looper.myLooper();
// 必须要有Looper,不然报异常
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// 指向 Looper 的 mQueue
mQueue = mLooper.mQueue;
// 赋值回调接口对象
mCallback = callback;
// 赋值是否异步
mAsynchronous = async;
}
public Handler(Looper looper, Callback callback, boolean async) {
// 此构造给那些在子线程创建 Handler 时使用,需要主动调用 Looper.prepare() 方法
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Handler 类主要面向开发者,所以我们需要全面掌握里面的方法。首先是构造函数,共 6 个构造函数,但是最终会往两个构造函数调用,这两个构造函数分别给主线程和子线程调用,具体看代码注释。
obtainMessage 方法
public final Message obtainMessage()
{
return Message.obtain(this);
}
public final Message obtainMessage(int what)
{
return Message.obtain(this, what);
}
public final Message obtainMessage(int what, Object obj)
{
return Message.obtain(this, what, obj);
}
public final Message obtainMessage(int what, int arg1, int arg2)
{
return Message.obtain(this, what, arg1, arg2);
}
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
return Message.obtain(this, what, arg1, arg2, obj);
}
Handler 里面有多个 obtainMessage 重载方法,用于获取 Message 对象,其实内部是调用 Message 的 obtain 静态方法的。所以我们也可以通过 Message 的静态 obtanin 方法来获取 Message 对象,最好不要直接用 new 关键字来创建 Message 对象,原因后面会说。
发送 Message 方法
public final boolean post(Runnable r)
{
// 延迟0秒发送
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean sendMessage(Message msg)
{
// 一般使用这个方法,延时值为0
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
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 static Message getPostMessage(Runnable r) {
// 创建 Message 对象并把Runnable对象赋值给 Message 的 callback
Message m = Message.obtain();
m.callback = r;
return m;
}
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
Handler 里面也有很多发送消息的方法,有 3 种发送方式:
post()类型的方法,传入的是Runnable对象,内部会通过getPostMessage()方法来封装Message对象,并把Runnable对象赋值给Message的callback成员对象。sendEmpty()类型的也不需要传入Message对象,内部会通过Message.obtain()方法获取Message对象。send()类型则需要外部传入Message对象。
无论调用何种方式发送消息,最终会调用 enqueueMessage 方法将消息对象入队,代码如下:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
// 把当前 Handler 传给 target 变量,用于分发回调
msg.target = this;
if (mAsynchronous) {
// 设置为异步消息
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
该方法会调用 MessageQueue 的 enqueueMessage 方法来将消息入队,注意方法内调用了 msg.target = this ,结合上面 Looper 的 loop 方法,会回调 Handler 的 dispatchMessage() 方法, dispatchMessage() 的源码如下:
// 消息分发
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 如果接收的消息中,携带这一个 callback ,就执行
handleCallback(msg);
} else {
if (mCallback != null) {
// 如果实例化 Handler 时实现了接口回调,就执行
if (mCallback.handleMessage(msg)) {
return;
}
}
// 执行这个方法
handleMessage(msg);
}
}
// 运行消息的 Callback 接口对象
private static void handleCallback(Message message) {
message.callback.run();
}
方法归纳:
首先判断
Message的callback对象是否为空,由之前分析得知,当用post方式发送消息时,callback则不为空,此时会运行callback的run方法,即post传入的Runnable的run方法。然后会判断
mCallback是否为空,如果不为空,则回调mCallback的handleMessage方法,此时的mCallback由创建Handler的时候通过构造方法传入,如果handleMessage方法返回true,则不执行最后的Handler的handleMessage方法,如果返回false,则执行。执行
Handler的handleMessage方法,该方法通常会被子类覆写。
总结(消息分发执行的优先级): post 的方式 > callback 方法 > 覆写方式 。
MessageQueue
上述讲到入队的时候,会调用 MessageQueue 的 enqueueMessage 方法,我们先看一下 MessageQueue 的构造方法,只有一个构造方法,如下:
MessageQueue(boolean quitAllowed) {
// 用来标识是否允许退出,主线程是不允许退出的,不然就会退出整个程序
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
入队方法源码如下:
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
// 如果已经在使用,即重复发送同一个消息,会报异常
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
// 已经退出,直接回收 Message ,返回 false
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();
return false;
}
// 标识在使用
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
// 单独处理链表头,队列为空或消息执行时间比之前的消息还早
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
// 把 msg 设置为新的链表头
msg.next = p;
// 将 mMessages 指向当前的链表头
mMessages = msg;
needWake = mBlocked;
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
// 如果遍历到最后一个消息或者执行时间比当前的消息早,则停止遍历
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
// 把当前消息插入相应的位置,插入的位置按照执行时间从早到晚排序
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// 唤醒线程,native 方法,添加Message 到 C环境中的消息队列中
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
方法归纳:
判断
Message的target对象,即Handler是否存在,不存在报异常。判断当前
Message是否已经在使用,是则报异常,避免重复发送同一个消息。判断是否已经退出循环了,如果是,则直接回收
Message,返回false,入队失败。标记当前
Message已经在使用,然后把当前Message插入到链表对应的位置上,按时间执行从早到晚排序。
在上述 Looper 的 loop 方法中,会不断循环地调用 MessageQueue 的 next 方法来做出队处理,获取 Message 来分发回调,next 方法如下:
Message next() {
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1;
// 0 表示不会阻塞,立即返回
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// 根据 nextPollTimeoutMillis 判断是否让其处于线程阻塞状态
// 取出一个消息 ,native方法,在C环境中创建了一个 NativeMessageQueue 数据对象
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
// 如果有消息屏障,会过滤掉后面的同步消息,找到下一个异步消息,默认都是同步消息
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
// 还没到执行时间,设置最长阻塞nextPollTimeoutMillis毫秒(超时),如果期间有程序唤醒会立即返回。
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 时间到了,下面的逻辑是把消息从链表中取出来
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
// 把当前消息指向的下一个消息的引用置为 null,
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
// 标记已经使用
msg.markInUse();
return msg;
}
} else {
没有消息的时候,一直阻塞不会超时
nextPollTimeoutMillis = -1;
}
// 如果调用了 quit 方法了,则返回 null ,Looper 就会结束循环
if (mQuitting) {
dispose();
return null;
}
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// 没有 idle handlers 要处理,Looper 继续阻塞等待
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// 处理一些不紧急的任务
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
//在处理 idle handler 的时候可能会有新的消息过来, 所以需要设置为 0 立即去取一次消息,
//当没有 idle handler 的时候会调 continue 阻塞。
nextPollTimeoutMillis = 0;
}
}
方法归纳:
如果没有消息或没到消息执行时间,会阻塞线程,否则唤醒线程。
获取最早的异步消息并返回。
如果调用过
quit退出方法,则返回空,Looper就会结束循环。处理一些不紧急的 idle handler 任务。
注意:主线程调用 quit 方法会报异常,默认不能退出,quit 方法代码如下:
void quit(boolean safe) {
// 主线程不允许退出循环
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
// 设置已经在退出
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
从源码可以看出当我们调用 quit 方法时,如果 safe 为 false 时,执行的是 removeAllMessagesLocked 方法,该方法主要是把 MessageQueue 消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过 sendMessageDelayed 或通过 postDelayed 等方法发送)还是非延迟消息。
当 safe 为 true 时,其内部调用的是 removeAllFutureMessagesLocked 方法,该方法只会清空 MessageQueue 消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让 Handler 去处理完成后才停止 Looper 循环。
Message
在整个 Handler 机制中,Message 就像信件一样在其中传递,作为线程消息传递的物件,我们看看 Message 类。
public final class Message implements Parcelable {
// 让接收者知道消息是做什么的
public int what;
// 用来传递整型参数
public int arg1;
// 用来传递整型参数
public int arg2;
// 用来传递复杂对象
public Object obj;
// 标记消息被使用
/*package*/ static final int FLAG_IN_USE = 1 << 0;
// 标记消息是异步的
/*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
// 消息当前的标记
/*package*/ int flags;
// 执行的时间
/*package*/ long when;
// 创建Handler时,target会被赋值给对应的 Handler
/*package*/ Handler target;
// Handler 用 post 消息发送消息时,会被赋值
/*package*/ Runnable callback;
// Bundle 对象
/*package*/ Bundle data;
// 指向的下一个 Message ,是个链表结构
/*package*/ Message next;
// 消息池链表头对象
private static Message sPool;
// 当前消息池的消息数量
private static int sPoolSize = 0;
// 消息池最大维护量
private static final int MAX_POOL_SIZE = 50;
public static Message obtain() {
// 尽量用这个方法来创建消息,消息池不为null ,则直接取出来复用消息
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();
}
// 回收资源
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
// 维护消息池
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
/*package*/ boolean isInUse() {
return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}
/*package*/ void markInUse() {
flags |= FLAG_IN_USE;
}
// 默认 public 构造方法,但是最好不要用
public Message() {
}
}
Handler消息机制的工作原理总结
通过Handler发送消息,此时会将Message入队列到MessageQueue中,并且唤醒等待的Looper
Looper获取的消息会投递给对应的Handler处理
创建与线程绑定的
Looper,同时会创建一个与之关联的MessageQueue用于存放消息。开启消息循环,从
MessageQueue中获取待处理消息,若无消息会阻塞线程。Handler会调用MessageQueue的enqueueMessage方法,将Message入队并且唤醒等待的Looper。Looper会循环调用MessageQueue的next方法,将Message出队并回调Message的target对象的dispatchMessage方法对Message进行分发处理,target就是对应的Handler对象。
时序图如下:

答疑解惑
其实以下这些疑问在上述分析中都能找到答案,这里再简要说明一下原因。
为什么 Handler 能够切换线程执行?
我们在子线程发送的消息,最终会在 Looper 所在的线程进行分发并回调,而 Looper 默认就是运行在主线程的,也就是说回调的 handleMessage() 方法是运行在主线程的,也就达到了线程切换的目的。因此,handleMessage() 方法执行的线程就是 Looper 所在的线程,而与 Handler 创建时所在的线程无关。
示例调用链:

为什么我们能在主线程直接使用 Handler,而不需要创建 Looper?
因为在程序启动的时候,系统会自动初始化 Looper 并调用 loop 方法,上述源码有讲到。
为什么创建 Message 对象推荐使用 Message.obtain()获取?
Message 类内维护了一个 Message 缓存池,用 obtain 方法时,会优先在池内取 Message 对象,达到节省开销、减少内存消耗的目的。缓存池的来源就在 Message 的 recycleUnchecked 方法中,也就是在 Message对象被回收资源时,会添加到缓存池内,缓存池最大量为 50 。
子线程可以创建 Handler 吗?
可以,创建 Handler 跟线程没关系,只需按照 Handler 的构造创建即可。因为系统只在主线程自动初始化 Looper 并调用 loop 方法,所以在子线程需要主动调用 Looper.prepare() 方法创建 Looper ,然后调用 loop() 方法开始循环工作。
子线程里使用示例代码:
// 子线程中发送消息
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
threadHandler = new Handler(Looper.myLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.d("MainActivity", "当前线程名称 == " + Thread.currentThread().getName());
return true;
}
});
Looper.loop();
Message message = Message.obtain();
message.what = 0;
message.obj = "普通消息方式";
mMyHandler.sendMessage(message);
}
}).start();
mMyHandler.postDelayed(new Runnable() {
@Override
public void run() {
threadHandler.sendEmptyMessage(1);
}
}, 2000);
Handler(Callback) 跟 Handler() 这两个构造方法的区别在哪?
上述分析有讲到,只是执行的优先级不同,callback 方法优先执行,而且如果返回 true ,还可以拦截 handleMessage 的回调。
Handler 引起的内存泄露原因以及最佳解决方案是什么?
Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露。这个泄露是因为 Message 会持有 Handler,而又因为 Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler 持有,这样最终就导致 Activity 泄露。
解决该问题的最有效的方法是:将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并及时移除所有消息,具体代码在上述 Handler 使用示例中有。