关于Handler,你应该知道的

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){
                
            }
        }
    }
    原文作者:zackyG
    原文地址: https://www.jianshu.com/p/8a891a9aa60a
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞