Handler源码分析

什么是Handler

  • Handler是Android SDK来处理异步消息的核心类。用来结合线程的消息队列来发送、处理“Message对象”和“Runnable对象”的工具。每一个Handler实例之后会关联一个线程和该线程的消息队列。当你创建一个Handler的时候,从这时开始,它就会自动关联到所在的线程/消息队列,然后它就会陆续把Message/Runnalbe分发到消息队列,并在它们出队的时候处理掉。

Handler的基本用法

private Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        //处理Message
    }
};

//发送消息
handler.sendMessage(message);
handler.post(runnable);

通过重写handleMessage方法我们就可以实例化这个handler。
从以上代码我们并没有看到Looper的身影,那么它有什么用呢?不是说Looper取出消息吗,这样看好像只要使用sendMessage或post发送消息handleMessage接收到处理不就可以了吗,Looper去哪了呢?其实looper已经在存在了,这是因为在主线程被创建的时候会自动创建一个Looper,如果是非主线程,则需要我们手动去创建。

假设我们在非主线程中使用Handler,那么可以这样写

class MyThread extends Thread{
    public Handler handler;
    @Override
    public void run() {
        Looper.prepare();
        handler = new Handler(){
            @Override
            public void handleMessage(Message msg){
                //处理消息
            }
        };
        Looper.loop();
    }
}

源码分析

Message的存储与管理

先看一下sendMessage和post方法的实现

sendMessage

public final boolean sendMessage(Message msg)
{
    return sendMessageDelayed(msg, 0);
}

post

public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

看一下getPostMessage(Runnable r)方法

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

殊途同归,两者其实都是使用的sendMessageDelayed这个方法,因为在post方法中实际会对Runnable对象封装成Message,这里注意一下使用getPostMessage方法对Runnable封装时是把Runnable对象放在了Message.callback里的,下面会讲为什么。

接着往下看我们会捋出来这样一条线
sendMessageDelayed(Message msg, long delayMillis)
——> sendMessageAtTime(Message msg, long uptimeMillis)
——>enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
——>Message.enqueueMessage(Message msg, long when)
OK,终于找到根源了,调用Handler的sendMessage和post方法最终会调用Message.enqueueMessage方法,同时,我们也发现终于和MessageQueue胜利会军,那么enqueueMessage方法是干嘛的呢,我们一起来看一下

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }

    synchronized (this) {
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }

        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            // Inserted within the middle of the queue.  Usually we don't have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

通过enqueueMessage方法我们可以看到这里是把发送的message按照待处理的剩余时间优先级塞到MessageQueue中。
到这里,我们就把发送消息的过程理清晰了,那么,handler又是怎么得到消息的呢?

Message的分发与处理

在上面Handler完成使用的例子中第12行我们看到调用了Looper.loop()方法,这个方法就是用来调度Message的,我们来看一下

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;

    // Make sure the identity of this thread is that of the local process,
    // and keep track of what that identity token actually is.
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    // Allow overriding a threshold with a system prop. e.g.
    // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
    final int thresholdOverride =
            SystemProperties.getInt("log.looper."
                    + Process.myUid() + "."
                    + Thread.currentThread().getName()
                    + ".slow", 0);

    boolean slowDeliveryDetected = false;

    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        // This must be in a local variable, in case a UI event sets the logger
        final Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }

        final long traceTag = me.mTraceTag;
        long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
        long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
        if (thresholdOverride > 0) {
            slowDispatchThresholdMs = thresholdOverride;
            slowDeliveryThresholdMs = thresholdOverride;
        }
        final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
        final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

        final boolean needStartTime = logSlowDelivery || logSlowDispatch;
        final boolean needEndTime = logSlowDispatch;

        if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
            Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
        }

        final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
        final long dispatchEnd;
        try {
            msg.target.dispatchMessage(msg);
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        if (logSlowDelivery) {
            if (slowDeliveryDetected) {
                if ((dispatchStart - msg.when) <= 10) {
                    Slog.w(TAG, "Drained");
                    slowDeliveryDetected = false;
                }
            } else {
                if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                        msg)) {
                    // Once we write a slow delivery log, suppress until the queue drains.
                    slowDeliveryDetected = true;
                }
            }
        }
        if (logSlowDispatch) {
            showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
        }

        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

        // Make sure that during the course of dispatching the
        // identity of the thread wasn't corrupted.
        final long newIdent = Binder.clearCallingIdentity();
        if (ident != newIdent) {
            Log.wtf(TAG, "Thread identity changed from 0x"
                    + Long.toHexString(ident) + " to 0x"
                    + Long.toHexString(newIdent) + " while dispatching to "
                    + msg.target.getClass().getName() + " "
                    + msg.callback + " what=" + msg.what);
        }

        msg.recycleUnchecked();
    }
}

这个方法的实现还挺多的,不过重点也就在那个死循环上,不停的从MessageQueue里取出Message并处理,在第57行我们看到这样一行代码

msg.target.dispatchMessage(msg);

msg.target就是发送该消息的handler,于是在这里又回调到Handler那边了,然后再看下dispatchMessage是做什么的

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

上面我们提到在发送消息的post方法中会把Runnable对象存放在Message.callback中,这里第二行的判断终于出现了不同,可以发现最终在处理消息时,handler对于Runnable消息是做了特殊处理的,先看对于Runnable对象Handler是怎么处理的

private static void handleCallback(Message message) {
    message.callback.run();
}

又回到了run方法,在run方法的重写里我们会实现对消息的处理,这个是我们自定义的,而对于sendMesssage方法发送的普通Message会通过回调我们重写的handleMessage方法对消息进行处理,到此可以发现,handler也得到了消息并做处理。

总结

Handler 的背后有着 Looper 以及 MessageQueue 的协助,三者通力合作,分工明确。
三者的职责关系简单概括一下:

  • Looper :负责关联线程以及消息的分发,在所关联的线程下从 MessageQueue 获取 Message,分发给 Handler ;
  • MessageQueue :链表实现的队列,负责消息的存储与管理,负责管理由 Handler 发送过来的 Message ;
  • Handler : 负责发送并处理消息,面向开发者,提供 API,并隐藏背后实现的细节。

扩展

创建 Message 实例的最佳方式

由于 Handler 极为常用,所以为了节省开销,Android 给 Message 设计了回收机制,所以我们在使用的时候尽量复用 Message ,减少内存消耗。
所以我们一般这样实例化Message:

Message msg = Message.obtain();
Message msg = handler.obtainMessage();

Message的回收机制

那么,以上两种方式和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();
}

可以看出这种方式是先尝试从sPool取一个Message,只有sPool为空的情况才会new一个Message对象,这么看sPool像是一个池子来存放可回收的Message,那么,sPool是从哪里回收的Message呢,看一下Looper.loop()方法的最后:

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

可以看到死循环最后调用了Message的recycleUnchecked()方法,看一下这个方法的实现:

void recycleUnchecked() {
    // Mark the message as in use while it remains in the recycled object pool.
    // Clear out all other details.
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = -1;
    when = 0;
    target = null;
    callback = null;
    data = null;

    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}

在这里Message得到了回收,放在sPool里。

Handler引起的内存泄漏

通常我们都会在一个Activity内部定义一个Handler的内部类:

public class MainActivity extends AppCompatActivity {
 
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                 ...
            }
        }
    };
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.lauout.activity_main);
 
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                ...
            }
        }, 10000);
 
    }
}
  1. 外部类Activity中定义了一个非静态内部类Handler,非静态内部类默认持有对外部类的引用。如果外部Activity突然关闭了,但是MessageQueue中的消息还没处理完,那么Handler就会一直持有对外部Activty的引用,垃圾回收器无法回收Activity,从而导致内存泄漏。
  2. 如上代码,在postDelayed中,我们在参数中传入一个非静态内部类Runnable,这同样会造成内存泄漏,假如此时关闭了Activity,那么垃圾回收器在接下来的1000000ms内都无法回收Activity,造成内存泄漏。

解决方案

  1. 将非静态内部类Handler和Runnable转为静态内部类,因为非静态内部类(匿名内部类)都会默认持有对外部类的强引用。
  2. 改成静态内部类后,对外部类的引用设为弱引用,因为在垃圾回收时,会自动将弱引用的对象回收。
public class HandlerActivity extends AppCompatActivity {
 
    private final MyHandler mHandler = new MyHandler(this);
 
    private static final Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            // 操作
        }
    };
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fourth);
 
        mHandler.postDelayed(mRunnable, 1000*10);
        
        finish();   
    }
 
 
    private static class MyHandler extends Handler {
        WeakReference<HandlerActivity> mWeakActivity;
 
        public MyHandler(HandlerActivity activity) {
            this.mWeakActivity = new WeakReference<HandlerActivity>(activity);
        }
 
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            final HandlerActivity mActivity = mWeakActivity.get();
            if (mActivity != null) {
                // 处理消息
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值