Handler

作者: _Rice_ | 来源:发表于2019-03-19 10:16 被阅读0次
    image.png

    Handler机制:

    是一个消息传递机制,作用是将子线程需要的UI操作,传递到UI线程执行,保证线程安全。

    image.png

    相关类介绍

    • Message:线程间通讯的数据单元。

    MessageQueue:消息队列,特点先进先出。存储Handler发送过来的消息(Message)

    • Handler:是一个消息处理器,将消息传递给消息队列,然后再由对应线程从消息队列中逐个取出数据,并执行

    • Looper:消息循环器,循环取出消息(Message),将取出的消息分发给对应的处理者(Handler)。
      特点:

    • 一个Handler只能拥有一个Looper。

    • 一个Looper可以绑定多个Handler

        public Handler(Callback callback, boolean async) {
           ...
            //关联Looper
            mLooper = Looper.myLooper();
            if (mLooper == null) {
                throw new RuntimeException(
                    "Can't create handler inside thread that has not called Looper.prepare()");
            }
            //关联MessageQueue
            mQueue = mLooper.mQueue;
            ...
        }
    

    在Handler的构造方法中,会关联Looper和MessageQueue(Looper的构造函数中会创建自己的MessageQueue)

    源码分析

    默认情况,消息队列只有一个,就是主线程的消息队列。这个线程由ActivityThread.main方法中创建,调用Looper.prepareMainLooper()创建,执行Looper.loop()来启动消息循环。

        public static void main(String[] args) {
    
           Looper.prepareMainLooper(); 
           // 1.创建主线程Looper
           ActivityThread thread = new ActivityThread(); 
           // 2. 创建主线程
           Looper.loop(); 
           // 3. 开启消息循环
    }
    
        //设置和获取Looper,Looper保存在ThreadLocal中
        public static void prepareMainLooper() {
            prepare(false);
            synchronized (Looper.class) {
                if (sMainLooper != null) {
                    throw new IllegalStateException("The main Looper has already been prepared.");
                }
                sMainLooper = myLooper();
            }
        }
        
        //设置Looper,只能调用一次
        private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(quitAllowed));
        }
    
       //Looper的构造函数中会创建自己的MessageQueue
       private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
        }
    
        //获取Looper
        public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
    

    可以看到Looper存储在ThreadLocal,这就实现了线程安全。Looper可以对应多个Handler

    /** 
      * 源码分析: Looper.loop()
      * 作用:消息循环,即从消息队列中获取消息、分发消息到Handler
      * 特别注意:
      *       a. 主线程的消息循环不允许退出,即无限循环
      *       b. 子线程的消息循环允许退出:调用消息队列MessageQueue的quit()
      */
      public static void loop() {
            
            ...// 仅贴出关键代码
    
            // 1. 获取当前Looper的消息队列
                final Looper me = myLooper();
                if (me == null) {
                    throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
                }
                // myLooper()作用:返回sThreadLocal存储的Looper实例;若me为null 则抛出异常
                // 即loop()执行前必须执行prepare(),从而创建1个Looper实例
                
                final MessageQueue queue = me.mQueue;
                // 获取Looper实例中的消息队列对象(MessageQueue)
    
            // 2. 消息循环(通过for循环)
                for (;;) {
                
                // 2.1 从消息队列中取出消息
                Message msg = queue.next(); 
                if (msg == null) {
                    return;
                }
                // next():取出消息队列里的消息
                // 若取出的消息为空,则线程阻塞
    
                // 2.2 派发消息到对应的Handler
                msg.target.dispatchMessage(msg);
                // 把消息Message派发给消息对象msg的target属性
                // target属性实际是1个handler对象
    
            // 3. 释放消息占据的资源
            msg.recycle();
            }
    }
    

    loop()是一个消息无限循环,不断从消息队列获取消息,将消息派发到对应的Handler

    public final class Message implements Parcelable {
    
        Handler target;
        Runnable callback;
        Message next;
    }
    
      /** dispatchMessage(msg)
      * 定义:属于处理者类(Handler)中的方法
      * 作用:派发消息到对应的Handler实例 & 根据传入的msg作出对应的操作
      */
      public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
    
            }
        }
    
       private static void handleCallback(Message message) {
            message.callback.run();
        }
    
    
       public void handleMessage(Message msg) {  
              ... // 创建Handler实例时复写
       } 
    
    

    dispatchMessage派发消息最终会调用HandlerMessage或者run方法处理

    1. 当调用Handler.post时msg.callback != null,会走run方法
    2. 当Message.obtain方法里设置时msg.callback != null,会走run方法
    3. 当Handler初始化时传入Callbackh时mCallback != null,会走mCallback.handleMessage(msg)方法
    4. 当前面两者都没有,直接调用sendMessage时,会走handleMessage(msg) 方法
    demo
    public class HandlerActivity extends AppCompatActivity {
        @BindView(R.id.content_tv)
        TextView mContentTv;
    
        Handler mHandler = new Handler() {
    
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.what == 1) {
                    mContentTv.setText((CharSequence) msg.obj);
                }
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_handler);
            ButterKnife.bind(this);
        }
    
        @OnClick({R.id.post, R.id.obtain, R.id.Handler_Callback_is_null, R.id.Handler_Callback_is_not_null})
        public void onClick(View view) {
            switch (view.getId()) {
                //当调用Handler.post时msg.callback != null,会走run方法
                case R.id.post:
                    new Thread() {
                        @Override
                        public void run() {
                            super.run();
                            mHandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    mContentTv.setText("post");
                                }
                            });
                        }
                    }.start();
                    break;
                //当Message.obtain方法里设置时msg.callback != null,会走run方法
                case R.id.obtain:
                    new Thread() {
                        @Override
                        public void run() {
                            super.run();
                            Message message = Message.obtain(mHandler, new Runnable() {
                                @Override
                                public void run() {
                                    mContentTv.setText("obtain");
                                }
                            });
                            mHandler.sendMessage(message);
                        }
                    }.start();
                    break;
                //当Handler初始化时传入Callback时mCallback != null,会走mCallback.handleMessage(msg)方法
                case R.id.Handler_Callback_is_null:
                    new Thread() {
                        @Override
                        public void run() {
                            super.run();
                            Message msg = Message.obtain();
                            msg.what = 1; // 消息标识
                            msg.obj = "Handler_Callback_is_null"; // 消息内存存放
                            mHandler.sendMessage(msg);
                        }
                    }.start();
                    break;
                //当前面两者都没有,直接调用sendMessage时,会走handleMessage(msg) 方法
                case R.id.Handler_Callback_is_not_null:
                    final Handler handler = new Handler(new Handler.Callback() {
                        @Override
                        public boolean handleMessage(Message msg) {
                            if (msg.what == 2) {
                                mContentTv.setText((CharSequence) msg.obj);
                            }
                            return true;
    
                        }
                    });
    
                    new Thread() {
                        @Override
                        public void run() {
                            super.run();
                            Message msg = Message.obtain();
                            msg.what = 2; // 消息标识
                            msg.obj = "Handler_Callback_is_not_null"; // 消息内存存放
                            handler.sendMessage(msg);
                        }
                    }.start();
                    break;
            }
        }
    }
    

    为什么可以直接post呢,因为post(Runnable r)会将Runnable包装成Message对象,并将Runnable对象设置给Message对象的callback,最好将Message对象插入消息队列中去。

        public final boolean post(Runnable r)
        {
           return  sendMessageDelayed(getPostMessage(r), 0);
        }
    
        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);
        }
    
        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;
            }
            //将消息插入MessageQueue
            return enqueueMessage(queue, msg, uptimeMillis);
        }
    

    Handler机制流程图

    image.png

    问题

    1、为什么不new Message()而采用Message.obtain()?

    因为Message内部维护了1个Message池,用于Message消息对象的复用,使用obtain()则是直接从池内获取,避免内存new 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();
        }
    
    2、Handler可以在子线程创建吗?

    通常Handler必须在主线程创建,因为Handler机制的主要作用是更新UI。当然也可以创建在子线程,那么就得自己手动去prepare和loop。

        new Thread(){
            @Override
            public void run() {
                super.run();
                //创建当前线程的Looper,并绑定到ThreadLocal中
                Looper.prepare();
                //创建Handler,关联Looper和MessageQueue
                Handler handler = new Handler();
                //启动消息循环
                Looper.loop();
            }
        }.start();
    
    3、Android中为什么主线程不会因为Looper.loop()里的死循环卡死?

    loop虽然是死循环,但是如果messagequeue里面没有消息的话,会休眠在native层那个nativePollonce方法

    问题参考:https://www.zhihu.com/question/34652589/answer/90344494?from=profile_answer_card](https://www.zhihu.com/question/34652589/answer/90344494?from=profile_answer_car

    4、如何避免不当导致的内存泄漏

    问题根源: 非静态匿名内部类持有外部类引用

    1、静态Handler内部类, 如果在handMessage方法里需要用到上下文, 进行弱化

    public class NoLeakActivity extends AppCompatActivity {
    
        private NoLeakHandler mHandler;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            mHandler = new NoLeakHandler(this);
    
            Message message = Message.obtain();
    
            mHandler.sendMessageDelayed(message,10*60*1000);
        }
    
        private static class NoLeakHandler extends Handler{
            private WeakReference<NoLeakActivity> mActivity;
    
            public NoLeakHandler(NoLeakActivity activity){
                mActivity = new WeakReference<>(activity);
            }
    
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        }
    }
    

    但是为什么为static类型就会解决这个问题呢?
    因为在java中所有非静态的对象都会持有当前类的强引用,而静态对象则只会持有当前类的弱引用。
    声明为静态后,handler将会持有一个Activity的弱引用,而弱引用会很容易被gc回收,这样就能解决Activity结束后,gc却无法回收的情况。

    2、Handler内部自带的remove方法

    学习参考:

    https://www.jianshu.com/p/b4d745c7ff7a

    https://www.zhihu.com/question/34652589/answer/90344494?from=profile_answer_card

    Android开发进阶从小工到专家

    相关文章

      网友评论

          本文标题:Handler

          本文链接:https://www.haomeiwen.com/subject/asnwmqtx.html