关于Handler,你应该知道的

作者: zackyG | 来源:发表于2019-03-18 22:26 被阅读7次

    Handler、Looper、Thread、Message、MessageQueue的关系

    每一个线程对象,都有且只有一个Looper对象与之关联。线程的Looper对象创建后,会自动创建一个MessageQueue作为该线程的消息队列。也就是说一个Thread对象对应一个Looper对象,对应一个MessageQueue。
    创建Handler时,如果没有指定与之关联的Looper对象,那就默认和创建Handler的线程的Looper对象相关联。这里需要提到两点:

    • 通常情况下,一个线程不会自动创建它关联的Looper对象。这意味着我们在子线程中创建Handler对象时,要先确定该线程的Looper对象是否已创建。如果Looper对象没有创建,则需调用Looper.prepare()来为线程创建对应的Looper对象。或者直接关联主线程的Looper对象。
    • 在Android系统中,UI主线程ActivityThread默认会自动创建关联的Looper对象。
      因为可以在一个线程里创建多个Handler,也就是说Looper和Handler是一对多的关系。一个Handler对象只能关联一个Looper对象。

    MessageQueue用来存放Handler发送的Message对象。MessageQueue由Looper管理。从MessagaQueue取出Message对象,分发给对应的Handler对象去处理。Looper通过Message对象的target属性,找到处理该消息的Handler对象。

    Message 和 Runnable

    当我们需要Handler发送一个Message时,不建议直接通过new Message()创建一个新的Message对象。更推荐使用Message.obtain()来获取Message对象。因为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对象。如此,可以避免创建过多的对象而产生GC问题。
    Handler不仅可以发送Message对象,还可以发送Runnable到消息队列。
    一般发送Message对象是用于在线程间传递数据。而发送Runnable则是用于执行定时任务。从Handler类的源码可以看出,发送Runnable,还是需要将其包装成Message对象。

    public final boolean post(Runnable r){
           return  sendMessageDelayed(getPostMessage(r), 0);
        }
    private static Message getPostMessage(Runnable r) {
            Message m = Message.obtain();
            m.callback = r;
            return m;
        }
    

    Callback 和 handleMessage

    细心的朋友会发现,Handler有这样一个构造函数,它需要一个Callback类型的参数,这个Callback是个接口,它也定义了一个handleMessage方法。

    public Handler(Callback callback) {
            this(callback, false);
        }
    public interface Callback {
            /**
             * @param msg A {@link android.os.Message Message} object
             * @return True if no further handling is desired
             */
            public boolean handleMessage(Message msg);
        }
    

    我们知道,Handler类本身也有一个handleMessage方法。那么他们之间的区别是什么呢

    public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    

    区别就在于,调用dispatchMessage方法处理消息时,是否需要执行Callback.handleMessage()方法。如果执行Callback.handleMessage(),则Handler的handleMessage()方法不会执行。

    Handler引发的内存泄漏

    我们刚接触Handler时,一般的用法是类似这样的:

    public class MainActivity extends Activity {
        private Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Thread mThread = new Thread(){
                @Override
                public void run() {
                    super.run();
                    try {
                        sleep(1000000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    handler.sendMessage(new Message());
                }
            };
            mThread.start();
        }
    }
    

    如此,在子线程中执行耗时的操作,需要较长的时间才能执行完。
    在java中,非静态内部类会默认持有外部类的强引用。这样的结果就是,在子线程执行耗时操作时,如果外部的Activity出现页面退出或关闭,那么原本应该被回收的Activity对象,会由于Handler对象还持有外部Activity对象的强引用,而导致Activity对象不能被回收,从而导致内存泄露。
    这个问题的解决方案是:
    1.将Handler类声明为静态类。如果处理消息需要用到外部Activity的引用,可以设为弱引用。

    private static class StaticHandler extends Handler{
            WeakReference<Activity> activity;
            public StaticHandler(Activity activity){
                this.activity = new WeakReference<>(activity);
            }
    
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (activity.get()!=null){
                    
                }
            }
        }
    

    相关文章

      网友评论

        本文标题:关于Handler,你应该知道的

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