Android Handler 详解

读前思考

学习一门技术或者看一篇文章最好的方式就是带着问题去学习,这样才能在过程当中有茅塞顿开、灯火阑珊的感受,记忆也会更深入。android

  1. 如何获取 Message 进行消息发送
  2. 使用 handler 形成内存泄露,如何避免?
  3. handler looper messageQueue的关系
  4. 程序是如何区分是将消息发给哪一个 Handler ?

概述

作 Android 开发确定离不开跟 Handler 打交道,它一般被咱们用来作主线程与子线程之间的通讯工具,而 Handler 做为 Android 中消息机制的重要一员也确实给咱们的开发带来了极大的便利。git

能够说只要有异步线程与主线程通讯的地方就必定会有 Handlerc#

一、 Handler 的基本使用

1.1 建立 Handler

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 并不必定执行。函数

1.2 Message 获取

获取 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,使用前两种方式进行建立。

1.3 Handler 发送消息

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 原理解析

1. 构造函数

实际上咱们在实例化 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;
    }
复制代码

2. Looper

经过调用 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();
        }
    }
复制代码

3. 小结

Handler 的背后有着 Looper 以及 MessageQueue 的协助,三者通力合做,分工明确。 尝试小结一下它们的职责,以下:

Looper :负责关联线程以及消息的分发在该线程下从 MessageQueue 获取 Message,分发给 Handler ;
MessageQueue :是个队列,负责消息的存储与管理,负责管理由 Handler 发送过来的 Message ;
Handler : 负责发送并处理消息,面向开发者,提供 API,并隐藏背后实现的细节。

Handler 发送的消息由 MessageQueue 存储管理,并由 Loopler 负责回调消息到 handleMessage()。

线程的转换由 Looper 完成,handleMessage() 所在线程由 Looper.loop() 调用者所在线程决定。

三、 总结

Handler 简单易用的背后藏着工程师大量的智慧,要努力向他们学习。

但愿看完本文能加深你对 Handler 的理解,对接下来学习有所帮助。

四、 参考

Handler

Android消息机制1-Handler(Java层)

Handler 都没搞懂,拿什么去跳槽啊?

相关文章
相关标签/搜索