习一门技术或者看一篇文章最好的方式就是带着问题去学习,这样才能在过程中有茅塞顿开、灯火阑珊的感觉,记忆也会更深刻。
做 Android 开发肯定离不开跟 Handler 打交道,它通常被我们用来做主线程与子线程之间的通信工具,而 Handler 作为 Android 中消息机制的重要一员也确实给我们的开发带来了极大的便利。
可以说只要有异步线程与主线程通信的地方就一定会有 Handler。
Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露。
这个泄露是因为 Message 会持有 Handler,而又因为 Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler 持有,这样最终就导致 Activity 泄露。
解决该问题的最有效的方法是:将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并及时移除所有消息。
示例如下:
- 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() 方法
- 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 的理解,对接下来学习有所帮助。
作者:kevenZheng
链接:https://www.jianshu.com/p/866fdbe9c8eb
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。