Android篇

Android消息机制Handler

2019-05-20  本文已影响0人  w达不溜w
love.GIF

当我们调用handler.sendMessage()发送一个Message时,实际上是将这个Message发送到MessageQueue中,然后与当前线程绑定的Looper会不断地从MessageQueue中取出新的Message,调用msg.target.dispatchMessage(msg)将消息分发到handlerMessage()中。

1.实例化Handler
//Handler
public Handler(Callback callback, boolean async) {
    //...
    //检查当前的线程是否有Looper,不存在就抛异常(主线程已为我们创建好了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持有一个MessageQueueu
    mQueue = mLooper.mQueue;
    //...
}

一个完整的Handler使用例子应该这样创建:

class LooperThread extends Thread {
    public Handler mHandler;

    public void run() {
        Looper.prepare();

        mHandler = new Handler() {
            //问题1:handler.handleMessage(msg)是在什么时候回调的呢?
            public void handleMessage(Message msg) {
                // 处理接收到的消息
            }
        };

        Looper.loop();
    }
}
2.Looper.prepare()

Looper提供了Looper.prepare()来创建Looper,借助ThreadLocal来实现与当前线程的绑定

//Looper
private static void prepare(boolean quitAllowed) {
    //Android规定一个线程只能够拥有一个与自己关联的Looper
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    //在当前线程绑定一个Looper
    sThreadLocal.set(new Looper(quitAllowed));
}

在Looper中,维持着一个Thread对象和MessageQueue对象

private Looper(boolean quitAllowed) {
    //创建一个新的MessageQueue quitAllowed参数表示这个Queue是否能够被退出
    mQueue = new MessageQueue(quitAllowed);
    //将线程对象指向了创建Looper的线程
    mThread = Thread.currentThread();
}
3.Looper.loop()

Looper.loop()会不断地从MessageQueue(MessageQueue.next())中获取Message,并调用msg.target.dispatchMessage(msg)回到Handler来分发消息。
Looper.loop()是个死循环,死循环并不是导致主线程卡顿的真正原因,真正原因是循环后面的事件没有得到分发。looper()方法最终会调用msg.target.dispatchMessage(msg)将事件分发出去,所以不会造成卡顿或者ANR。

//Looper
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 (;;) {
        //不断地从MessageQueue获取消息
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        // ...
        try {
            //问题2:Looper.loop()死循环中的msg.target是什么时候被赋值的呢?
            msg.target.dispatchMessage(msg);
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            //...
        }
        //...
        //回收message
        msg.recycleUnchecked();
    }
}

msg.target.dispatchMessage(msg)中的msg.target就是发送该消息的Handler,这样就回调到了Handler那边去了

//Handler
public void dispatchMessage(Message msg) {
    //msg.callback是Runable
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        //可以利用 Callback 这个拦截机制来拦截 Handler 的消息。
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //问题1:回调到Handler的handlerMessage方法
        handleMessage(msg);
    }
}
4.handler.sendMessage()

无论是handler.sendMessage(msg)还是handler.sendEmptyMessage(what),最终都追溯到以下方法

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
   //引用Handler中的MessageQueue
    //这个MessageQueue就是创建Looper时被创建的MessageQueue
    MessageQueue queue = mQueue;
    if (queue == null) {
        RuntimeException e = new RuntimeException(
            this + " sendMessageAtTime() called with no mQueue");
        Log.w("Looper", e.getMessage(), e);
        return false;
    }
    //将新来的Message加入到MessageQueue中
    return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    //问题2:msg.target被赋值的时机:在handler.sendMessage(msg)后,执行enqueueMessage的时候
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}
5.关于Handler引起的内存泄漏
handler.png

可以看到IDE标黄了代码,并给出了提示。
假如我们用Handler发送延时消息,延时期间用户关闭了Activity,Message依旧会由Handler进行处理,即Message会持有Handler,而又因为Java的特性,非静态内部类会持有外部类的强引用,使得Activity会被Handler持有,这样导致了Activity无法被GC识别回收,这样最终导致了Activity泄漏。
解决该问题得有效方案:将Handler定义为静态内部类,在内部类中持有Activity的弱引用,并是移除所有消息。(被弱引用关联的对象只能存活到下一次垃圾回收之前,被销毁的Activity会被回收内存)

private static class SafeHandler extends Handler {

    private WeakReference<HandlerActivity> mActivity;

    public SafeHandler(HandlerActivity activity) {
        this.mActivity = new WeakReference(activity);
    }

    @Override
    public void handleMessage(final Message msg) {
        HandlerActivity activity = mActivity.get();
        if (activity != null) {
            activity.handleMessage(msg);
        }
    }
}

并在Activity.onDestory()前移除消息,加一层保障

@Override
protected void onDestroy() {
  safeHandler.removeCallbacksAndMessages(null);
  super.onDestroy();
}

注:以上系统源码基于 Android 28

上一篇下一篇

猜你喜欢

热点阅读