Handler 源码分析

Handler原理解析

Handler做为Android线程间通信的基础,是开发与面试必备技能。与之相关的有AsynTask,EventBus等

  • 子线程中使用Handler与主线程通信
  • 如何创建子线程自己的Handler来进行通信
  • AsynTask,EventBus等对于Hangler的应用

一、子线程中使用Handler与主线程通信

1. Looper的初始化(主线程)

如果了解过应用启动流程的同学,应该知道ActivityThread的main方法才是应用的入口,在这里我们就不细说了。主线程的Looper对象,就是在ActivityThread的main方法中进行的初始化操作,Looper的初始化主要包含两步:

  1. 初始化looper对象
  2. looper开始轮询
public final class ActivityThread {  
    public static void main(String[] args) {  
        ...  
        //1. 初始化looper对象
        Looper.prepareMainLooper();
        

        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        //建立Binder通道 (创建新线程)
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        
        // 2. looper开始轮询
        Looper.loop();   
        ...
    }
}

prepare方法创建了Looper对象,将主线程与Looper对象绑定,存入静态变量sThreadLocal对象中 ,并以sThreadLocal为key,Looper为value创建ThreadLocalMap,然后赋值给主线程的成员变量threadLocals。也就是说,prepare完成了主线程与Looper的绑定关系

public final class Looper {
    static final ThreadLocal sThreadLocal = new ThreadLocal();
    private static Looper sMainLooper;  // guarded by Looper.class
    
    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));
    }
    
    ... 
    
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
    
} 

这里我们看一下Looper的构造方法,创建了消息队列和当前线程变量,其中变量quitAllowed代表主线程的消息队列不允许停止

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

那么ThreadLocal内部怎么实现绑定线程与Handler的关系的呢?
在get()方法中,首先会获取当前的线程,以及其成员变量t.threadLocals,threadLocals是ThreadLocalMap类型,存储了当前线程相关联的所有的ThreadLocal对象,以及与之绑定的范型的实例,即Handler对象。如果获取到线程的threadLocals为空,或者threadLocals中保存的未保存当前ThreadLocal内部的Looper,则会继续执行setInitialValue()

setInitialValue()方法会调用

public class ThreadLocal {
    // 1.步骤一,ActivityThread初始化Looper时会调用,然后执行createMap()
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    
    // 2.步骤一,以ThreadLocal为key,Looper为value创建了ThreadLocalMap,并赋值给主线程的局部变量
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

    // 3. 步骤二,在调用Looper.myLooper()时返回主线程绑定的Looper
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
    
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
    
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }
}

public class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals = null;
}

第二步操作Looper.loop()方法会获取与线程相关联的Looper,开启一个循环,不断的轮询looper内部消息队列中消息,并进行分发操作
思考:为何loop()方法不会阻塞主线程

    public static void loop() {
         final Looper me = myLooper();
         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);
            } finally {
            }
        }
    }
    
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
    

2. Handler的创建与调用

handler(主线程)的创建步骤如下:

  1. 在主线程中使用new Handler()创建handler
  2. 子线程中使用handler.sendMessage(msg)发消息
  3. 在主线程的handler的handlerMessage中处理消息

主线程中创建Handler时,调用的是无参数构造方法,通过myLooper()获取到与当前线程绑定的looper对象

public class Handler {
    
    public Handler() {
        this(null, false);
    }
    
    public Handler(Callback callback, boolean async) {
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
    }
}

发送消息时会调用sendMessage(msg)方法,最终会调用queue.enqueueMessage()将消息放入消息队列

    public final boolean sendMessage(Message msg){
        return sendMessageDelayed(msg, 0);
    }
    
    ... 
    
    public boolean sendMessageAtTime(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(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }


MessageQueue调用enqueueMessage()时,将新消息加入消息队列,并且更新上一个消息和下一个消息

public final class MessageQueue {
    Message mMessages;
    
    // 
    boolean enqueueMessage(Message msg, long when) {
         synchronized (this) {
            Message p = mMessages;
            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 {
                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);
            }
         }
    }
}

此时因为主线程的looper的loop()方法一直处于等待执行,当接收到新消息时会分发消息
msg.target.dispatchMessage(msg),target为发送消息的Handler对象,handler会调用
初始化Handler时复写的handleMessage(msg)方法,将msg传出

    public void dispatchMessage(Message msg) {
        ...
        handleMessage(msg);
       
    }
    //实现为空
    public void handleMessage(Message msg) {
    }

二、如何创建子线程自己的Handler来进行通信

在主线程中,我们调用了无参数的Handler构造方法,如果在子线程中调用,就会抛出RuntimeException异常,因为我们没有初始化Handler相关的Looper对象。那么子线程中我们需要自己初始化looper,然后调用有参构造方法创建Handler

public class MyHandlerThread extends Thread{
    Looper looper = null;

    @Override
    public void run(){
        Looper.prepare();
        looper.loop();
    }
}

//调用方法
public void init(){
    MyHandlerThread handlerThread = new MyHandlerThread();
    handlerThread.start();
    
    Handler threadHandler = new Handler(handlerThread.looper){
        @Override
        public void handleMessage(Message msg){
                
        }
    };
    threadHandler.sendMessage(msg);
}

其实google已经帮我们实现了以上操作,HandlerThread的run方法中会调用Looper.prepare()与Looper.loop();创建当前的线程相关的Looper

public class HandlerThread extends Thread {

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
}

你可能感兴趣的:(Handler 源码分析)