【Android】Handler机制、源码分析、内存泄漏

Handler机制

Handler机制也可说是异步消息机制,由Message,Handler,MessageQueue,Looper组成。
Message:
Message是线程间传递的消息,可携带少量信息,在不同线程间交换数据。

Handler:
Handler是处理者,可在子线程中发送Message消息,在UI线程中处理Message消息。子线程中发送的Message消息最终传递到Handler#handlerMessage()方法进行处理。

MessageQueue:
MessageQueue是消息队列,用于存放所有Handler发送的消息,每个线程只有一个MessageQueue对象。

Looper:
Looper循环管理MessageQueue中的消息,每当有消息时就将其传递给Handler#handlerMessage()方法,每个线程只有一个Looper对象。

整体流程:

  1. Handler发送Message
  2. MessageQueue#enqueueMessage()存放Message->
  3. Looper循环调用MessageQueue#next()取出Message->
  4. Message的处理者Handler调用Handler#dispatchMessage()传递消息->
  5. Handler#handlerMessage处理Message

源码

1. 初始化对象
Handler(Looper looper)和Handler(Looper looper, Callback callback)最终调用Handler(Looper looper, Callback callback, boolean async)将传入参数赋值

    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

Handler()与Handler(Callback callback)最终调用Handler(Callback callback, boolean async),这个构造方法里的Looper是通过Looper.myLooper()去获取的。

    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
		//设置Looper
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

Looper

    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

一路追溯下去可以发现是ActivityThread的main方法调用了Looper#prepareMainLooper()
ActivityThread

    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();
		...
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

Looper#prepareMainLooper()方法调用了prepare(false),将主线程的Looper设置进了ThreadLocal中,Looper.myLooper()获取的就是main方法设置进去的Looper,这也就是为什么无参Handler初始化的对象发送的消息是在主线程中接受。
Looper

    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    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));
    }

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

2. 发送消息
send消息和post任务最终都是调用Handler#enqueueMessage(),调用方法的时候会把当前Handler设置到Message的target里用于后续消息传递

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

在看对象初始化的时候我们看到在ActivityThread的main方法里还调用了Looper.loop(),该方法里进行无限循环,只要获取到Message就调用target处理者Handler#dispatchMessage()方法

    public static void loop() {
        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 (;;) {

            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
			...
            try {
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
			...
            msg.recycleUnchecked();
        }
    }

Handler里的dispatchMessage方法就是调用handleMessage方法或执行任务,就可以在实现的handleMessage方法里或在Runnable的run方法里处理事件了

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

内存泄漏

以前习惯写法的Handler会持有Activity的引用,在执行Handler#sendMessageDelay()等设定delay时间的方法时退出,Activity不再被使用,但Handler持有Activity引用,导致Activity无法被回收。
常用解决方法是使用静态内部类+弱引用的方式:

    private static class MyHandler extends Handler {
        private WeakReference<HandlerActivity> weakReference;

        public MyHandler(HandlerActivity handlerActivity) {
            this.weakReference = new WeakReference<>(handlerActivity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            HandlerActivity activity = weakReference.get();
            if (activity != null) {
                //TODO
            }
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章