学习一门技术或者看一篇文章最好的方式就是带着问题去学习,这样才能在过程当中有茅塞顿开、灯火阑珊的感受,记忆也会更深入。android
作 Android 开发确定离不开跟 Handler 打交道,它一般被咱们用来作主线程与子线程之间的通讯工具,而 Handler 做为 Android 中消息机制的重要一员也确实给咱们的开发带来了极大的便利。git
能够说只要有异步线程与主线程通讯的地方就必定会有 Handler。c#
Handler 容许咱们发送延时消息,若是在延时期间用户关闭了 Activity,那么该 Activity 会泄露。bash
这个泄露是由于 Message 会持有 Handler,而又由于 Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler 持有,这样最终就致使 Activity 泄露。异步
解决该问题的最有效的方法是:将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并及时移除全部消息。async
示例以下:ide
public class Part8HandlerActivity extends AppCompatActivity {
private Button bt_handler_send;
private static class MyHandler extends Handler {
//弱引用持有Part8HandlerActivity , GC 回收时会被回收掉
private WeakReference<Part8HandlerActivity> weakReference;
public MyHandler(Part8HandlerActivity activity) {
this.weakReference = new WeakReference(activity);
}
@Override
public void handleMessage(Message msg) {
Part8HandlerActivity activity = weakReference.get();
super.handleMessage(msg);
if (null != activity) {
//执行业务逻辑
Toast.makeText(activity,"handleMessage",Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_part8_handler);
//建立 Handler
final MyHandler handler = new MyHandler(this);
bt_handler_send = findViewById(R.id.bt_handler_send);
bt_handler_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
//使用 handler 发送空消息
handler.sendEmptyMessage(0);
}
}).start();
}
});
}
@Override
protected void onDestroy() {
//移除全部回调及消息
myHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
}
复制代码
注意:单纯的在 onDestroy 移除消息并不保险,由于 onDestroy 并不必定执行。函数
获取 Message 大概有以下几种方式:工具
Message message = myHandler.obtainMessage(); //经过 Handler 实例获取
Message message1 = Message.obtain(); //经过 Message 获取
Message message2 = new Message(); //直接建立新的 Message 实例
复制代码
经过查看源码可知,Handler 的 obtainMessage() 方法也是调用了 Message 的 obtain() 方法oop
public final Message obtainMessage()
{
return Message.obtain(this);
}
复制代码
经过查看 Message 的 obtain 方法
public static Message obtain(Handler h) {
//调用下面的方法获取 Message
Message m = obtain();
//将当前 Handler 指定给 message 的 target ,用来区分是哪一个 Handler 的消息
m.target = h;
return m;
}
//从消息池中拿取 Message,若是有则返回,不然建立新的 Message
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();
}
复制代码
为了节省开销,咱们在使用的时候尽可能复用 Message,使用前两种方式进行建立。
Handler 提供了一些列的方法让咱们来发送消息,如 send()系列 post()系列 。
不过无论咱们调用什么方法,最终都会走到 MessageQueue.enqueueMessage(Message,long) 方法。 以 sendEmptyMessage(int) 方法为例:
//Handler
sendEmptyMessage(int)
-> sendEmptyMessageDelayed(int,int)
-> sendMessageAtTime(Message,long)
-> enqueueMessage(MessageQueue,Message,long)
-> queue.enqueueMessage(Message, long);
复制代码
从中能够发现 MessageQueue 这个消息队列,负责消息的入队,出队。
实际上咱们在实例化 Handler 的时候 Handler 会去检查当前线程的 Looper 是否存在,若是不存在则会报异常,也就是说在建立 Handler 以前必定须要先建立 Looper 。
public Handler(Callback callback, boolean async) {
//检查当前线程是否持有 Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
//Looper 持有一个 MessageQueue
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
复制代码
经过调用 Looper.prepare() 能够在当前线程建立 Looper,而后调用 Looper.loop() 让消息队列循环起来。
代码以下:
private static void prepare(boolean quitAllowed) {
//若是当前线程已经存在 Looper,则会抛出异常
//在主线程中调用 prepare 就会抛出此异常,由于主线程已经存在 Looper
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//将建立的 Looper 对象存入线程的 ThreadLocal 中,保持惟一
sThreadLocal.set(new Looper(quitAllowed));
}
复制代码
Looper.loop() 相关代码
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.");
}
//而后获取消息队列
final MessageQueue queue = me.mQueue;
//..
for (;;) {
//不断从 MessageQueue 中获取消息
Message msg = queue.next(); // might block
//
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//..
try {
// 经过 handler 发送消息
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
//..
}
//..
//回收 Message
msg.recycleUnchecked();
}
}
复制代码
Handler 的背后有着 Looper 以及 MessageQueue 的协助,三者通力合做,分工明确。 尝试小结一下它们的职责,以下:
Looper :负责关联线程以及消息的分发在该线程下从 MessageQueue 获取 Message,分发给 Handler ;
MessageQueue :是个队列,负责消息的存储与管理,负责管理由 Handler 发送过来的 Message ;
Handler : 负责发送并处理消息,面向开发者,提供 API,并隐藏背后实现的细节。
Handler 发送的消息由 MessageQueue 存储管理,并由 Loopler 负责回调消息到 handleMessage()。
线程的转换由 Looper 完成,handleMessage() 所在线程由 Looper.loop() 调用者所在线程决定。
Handler 简单易用的背后藏着工程师大量的智慧,要努力向他们学习。
但愿看完本文能加深你对 Handler 的理解,对接下来学习有所帮助。