handler源码解析与面试扩展

Handle在Android中的定位

1.所有的事件都是通过handle message 分发的。
通过launcher (app) 管理其他应用APP的启动,利用zygote进程,fork一个新进程,分配jvm虚拟机(保证数据完整性,安全性)。每个java类,都是通过一个main()函数启动,我们的应用APP也是通过ActivityThread.main() 函数启动,并且在此函数中,构建了Looper实例对象,执行了Looper.loop() 函数,用来不断循环的取出消息。所以主线程中默认有Looper,创建new Handle,不需要自定义Looper对象。
ActivityThread main()

 public static void main(String[] args) {
       ....
        Looper.prepareMainLooper(); //构造Looper实例对象

      .....
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler(); //返回 new handler()创建的实例对象
        }

      .....
        Looper.loop(); //死循环,轮播消息,分发给handle.handleMessage

     ....
    }
333.png

Handle工作流程

1.子线程中 Handle发送消息
2.MessageQueue把消息加入队列(MessageQueue只是一个容器,没有线程)
3.主线程 中的 Looper把消息从队列中 取出来,分发给handle
4.handle在回调函数中 处理数据(主线程)
5.如此一个循环步骤,实现了线程之间的通信

777.png
111.png

源码解析

1.handler 发送消息 ,最终会调到sendMessageAtTime--》enqueueMessage()
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

  private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
 //msg消息 拥有handle,如果handle是内部类,那么有可能造成内存泄露
        msg.target = this;
        ....
        return queue.enqueueMessage(msg, uptimeMillis);
    }
2.MessageQueue enqueueMessage() 把消息加入队列

MessageQueue 是个单链接优先级队列

666.png
999.png
 boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }

        synchronized (this) {//同步锁,保证数据队列的线程安全
           ....

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
           //判断消息的优先级,确定插入队列位置
            if (p == null || when == 0 || when < p.when) {
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
              
                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) { //messageQueue为null时,进入睡眠状态
                nativeWake(mPtr);
            }
        }
        return true;
    }
3.Looper .prepare() 构建Looper实例对象,加入ThreadLocal

Looper .prepare() 构造Looper()实例对象,Looper()是私有构造函数
整个APP 只有一个ThreadLocal 对象实例,利用ThreadLocalMap存储Looper实例,保证一个线程,只有一个Looper

888.png
static final ThreadLocal sThreadLocal = new ThreadLocal();
//sThreadLocal  存储Looper实例的实现函数
 public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
      //key是当前线程,value是Looper实例,所以一个线程只有一个Looper
            createMap(t, value); 
    }


 public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) { //一个线程只有一个Looper
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

  //构建 主线程的Looper,在ActivityThread.main()调用,
 //所以主线程new handle,不需要对Looper进行实例化
    @Deprecated
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

//以thread为key,在ThreadLocalMap中取出存储的Looper实例对象
public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

    /**
     * 获取主线程的Looper对象实例
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }
4. Looper.loop() 循环遍历messageQueue,取出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.");
        }
        ...

        for (;;) { //利用死循环,循环取出messageQueue中的message,分发给handle的接口函数handleMessage()
            if (!loopOnce(me, ident, thresholdOverride)) {
                return;
            }
        }
    }

 private static boolean loopOnce(final Looper me,
            final long ident, final int thresholdOverride) {
        Message msg = me.mQueue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return false;
        }
    ...
        try {
         //调用handle dispatchMessage
            msg.target.dispatchMessage(msg);
           ...
        } catch (Exception exception) {
          ....
        } finally {
            .....
        }
       ....
       
        //对message进行清空处理,复用内存,避免内存碎片,产生内存抖动,造成oom
        msg.recycleUnchecked();

        return true;
    }

//messageQueue 通过next() 取出消息
 Message next() {
    
        final long ptr = mPtr;//是否进入睡眠状态
        if (ptr == 0) {
            return null;
        }
         ......
        for (;;) {
           .....

            synchronized (this) {
               ....
                Message prevMsg = null;
                Message msg = mMessages;
               ......
                if (msg != null) {
                    ....
                    } else {
                        ......
                        return msg;
                    }
                }
               .....
              
                if (mQuitting) { //Looper 调用了quit() 清空全部message信息
                    dispose();
                    return null;
                }
               ..........
        }
    }



//handle dispatchMessage,把message 回调给handleMessage()函数
 public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
6.Message 类的 obtain(),享元设计模式,复用内存
  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对象,数据清空,复用内存
 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 = UID_NONE;
        workSourceUid = UID_NONE;
        when = 0;
        target = null;
        callback = null;
        data = null;

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

面试题解析

1.一个线程有几个Handler?

可以有很多个Handler,在主线程中 new Handler(), 在子线程中 new Handle(Looper) 必须传入对应Looper对象。

2.一个线程有几个Looper?怎么保证

一个线程只能有一个Looer,通过ThreadLocal的ThreadLocalMap来保证,在Looper实例化的时候,会把Looper实例化对象存在ThreadLocalMap中,key是当前Thread。下次再调用Looper实例化函数prepare(),会先从ThreadLocalMap 读取以thread为key的数据,如果不为空,抛出异常。

private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) { //一个线程只有一个Looper
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

3,Handler内存泄露的原因?为啥其他内部类没有这个问题?

内部类默认持有外部类对象,所以handler实例默认持有外部activity。
在handler发送消息的函数中,把handler对象赋值给了message,所以message持有了handler。而message的执行是不确定的,按照顺序执行的,如此一来即使activity退出页面,也不会被内存回收,造成内存泄露。可以使用静态内部 Handler来解决这个问题。
其他内部类 比如RecycleView adapter的viewHolder 为什么没有造成内存泄露,因为他跟着activity的生命周期,当activity退出,也会退出。

4.为何主线程可以直接new Handler(),子线程中想要new Handler()需要做哪些准备?

Handler中必须有一个Looper对象。
因为主线程在activityThread 的main()函数执行的时候,就已经创建了Looper的对象实例,并且调用了Loope.loop()函数,所以不需要在对Looper对象操作。
想要在子线程中 new Handler()实例对象,必须初始化mLooper = Looper.prepar()构建Looper实例对象,new Handler(mLooper) 创建handler对象,然后调用Looper.loop() 循环取出消息

5.子线程中维护的Looper,消息队列无消息的时候的处理方案是什么?有什么用?

消息队列无消息的时候就进入睡眠状态,Looper.loop死循环,取出message 为null,就退出本次循环,然后再来一次。Looper.quit()调用MessageQueue的quit()

//Looper.quit()
 public void quit() {
        mQueue.quit(false);
    }

//MessageQueue的quit()
void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked(); //清除所有的message数据
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr); //进入睡眠状态
        }

 private void removeAllMessagesLocked() {
        Message p = mMessages;
        while (p != null) {
            Message n = p.next;
            p.recycleUnchecked(); //清空数据,复用内存
            p = n;
        }
        mMessages = null;
    }

    }

6.存在多个Handler 往messageQueue 中添加数据,内部是如何确保线程安全的?

利用锁来保证线程安全,synchronized 同步锁,也称之为内置锁,有jvm实现上锁和解锁操作。
messageQueue.enqueueMessage(),利用 synchronized (this) 对整个messageQueue对象上锁,对象里面的所有函数 代码块都会受到限制。并且一个线程中只有一个Looper,所有也只有一个可以操作messageQueue的地方,保证一个线程只有一个messagQueue对象。

   boolean enqueueMessage(Message msg, long when) {
      
        synchronized (this) {
           ....
                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;
    }

7.使用Message时应该如何创建它?

为了保证内存的复用,Message使用了享元设计模式,通过提供的obtain()函数来构建Message对象,优先使用已分配内存并且清空数据的Message对象,如果不存在这样的内存对象,就new Message(只是个空函数) 构建message 对象,分配内存。
在message对象被分配给handle之后,会调用 msg.recycleUnchecked();清空数据,复用内存。

8.Looper死循环为什么不会导致应用卡死。

anr是应用无响应,当在主线程 执行点击操作 5s之内没有响应, 或者广播10s,服务20s,执行耗时操作没有结束任务,就会报出ANR 应用无响应 弹窗。
无论是点击事件,还是Anr事件都是一个message,都需要Looper循环取出的。
比如 一个点击事件,生成一个message,在5s之内没有处理该message,就会再发一个Anr message,因为他的优先级比较高,所以会先取出ANR的消息,展示弹窗。
所以Looper的死循环和Anr不是一个层级的问题。

9.Handler 是怎么实现多线程通信的?

子线程中,通过主线程创建的handler对象实例发送消息,调用messagQueue把消息加入消息队列。messagQueue只是个容器,没有线程的区别。
因为主线程创建的handler对象实例,所以handler 对应的looper就是ActivityThread main() 函数创建的looper。
主线程中Looper.loop() 调用messagQueue.next() ,获取对应的message消息,通过handler.dispatchMessage() ,给回调函数handleMessage() 赋值。
子线程发送数据,主线程取出数据,就这样完成了线程之间的通信。

Handler的扩展使用

HandlerThread

HandlerThread 是Thread的子类,就是一个线程,只是在内部帮助实现了Looper实例化。
方便使用,保证了线程安全。


public class HandlerThread extends Thread {
   .....
    @Override
    public void run() {
      ...
        Looper.prepare();
        synchronized (this) {//保证线程安全
            mLooper = Looper.myLooper();
            notifyAll();//激活所有等待的线程,进入就绪状态
        }
       ....
        Looper.loop();
      .....
    }
    
  
    public Looper getLooper() {
       .....
        synchronized (this) { //保证线程安全,避免取出空looper
            while (isAlive() && mLooper == null) {
                try {
                    wait(); //进入等待状态
                } catch (InterruptedException e) {
                   .....
                }
            }
        }
      ......
        return mLooper;
    }

    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) { //内部创建Handler实例对象
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

   ......
}

IntentService

是Service的子类,一般用于处理后台耗时任务。内部封装 HandlerThread实现子线程处理耗时任务。
内部创建了Handler 实例对象,用来分发数据给回调函数 onHandleIntent((Intent)msg.obj);
一个任务分成几个子任务,子任务按照顺序先后执行,子任务全部执行结束后,这项任务才算成功。intentService就能完成这个任务,并且很好的管理线程,保证只有一个子线程处理工作,而且是一个一个完成任务,有条不紊的顺序执行

@Deprecated
public abstract class IntentService extends Service {
....

//子线程 handler
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);//回调数据
            stopSelf(msg.arg1);
        }
    }
....

    @Override
    public void onCreate() {
      
        super.onCreate();
        //构建线程
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        //构建子线程的handler
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

   ....

    @Override
    public void onDestroy() {
      //退出循环
        mServiceLooper.quit();
    }

   ....

    @WorkerThread //因为handler是子线程创建的,所以此函数也工作在子线程,可以执行耗时操作
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

你可能感兴趣的:(handler源码解析与面试扩展)