欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android handler源码解析

程序员文章站 2022-07-14 16:46:28
...

handler通信是一个内存共享的方案

Handler

public class Handler {
    
    public Handler(@Nullable Callback callback, boolean async) {
        // 拿到Looper里ThreadLocal储存的Looper对象
        mLooper = Looper.myLooper();
    }
    
}

public final class Looper {
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    
     public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
}

threadlocal中的代码可以看出get()方法会返回一个Looper对象

public class ThreadLocal<T> {
    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;
    }
    
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
}

上面的代码可以简化为:

public class ThreadLocal<T> {
    public T get() {
        ThreadLocalMap map = t.threadLocals;
        if(map != null) {
            return map.getEntry(this);
        }
         t.threadLocals = new ThreadLocalMap(this, firstValue)
        return null;
    }
}

可以看出handler构造方法里做的事,获取一个当前线程对应的Looper对象,并且这个Looper对象不能为空,否者抛出异常

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

因此,在子线程中创建Handler的时候要先构建一个当前线程对应的Looper,即执行Looper.prepare()方法,并且每个线程该方法只能执行一次:

public final class Looper {
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    
    // 静态方法,和sThreadLocal结合就可以看出一个线程只对应一个Looper实例
    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));
    }
}

此时注意,Looper中有有一个特殊的prepare方法,就是prepareMainLooper

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

创建Looper时,构造方法中自动创建一个MessageQueue对象

public final class Looper {
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
    }
}

2、发送一个Message消息

发送消息最后都会调用这个方法:

    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.target = this; // 这边的msg会持有一个handler对象
        return queue.enqueueMessage(msg, uptimeMillis);
    }

这里的message持有一个handler对象,所以使用内部类创建handler的时候有可能会造成内存

持有
内部类会默认持有外部类的引用
msg
handler
activity

继续看源码,sendmessage最后会调用MessageQueue的enqueueMessage方法,这个方法做的事就是往当前线程对应的MessageQueue队列中插入message:

 boolean enqueueMessage(Message msg, long when) {

        synchronized (this) { // 内置锁
           
            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) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

MessageQueue是个单链表,优先级队列。

现在,消息已经被发送到消息队列里了,接下来就是消费这个事件。

4、消费事件

loop() 是一个静态方法,调用loop()方法就会开启一个死循环

public final class Looper {
    public static void loop() {
        final Looper me = myLooper();
        final MessageQueue queue = me.mQueue;
    }
}

通过这个死循环把消息回调给handler

public final class Looper {
    public static void loop() {
          for (;;) {
            Message msg = queue.next(); // 取出队列最前面的消息
             if (msg == null) {
                //消息位空的时候才推出循环
                return;
            }
            ...
            // msg.target就是将该消息发送进来的handler,通过这个handler把消息再回调回去
            msg.target.dispatchMessage(msg);
    }
}

最终会调用handleMessage(msg)这个方法,也就是我们平时创建handler的时候重写的这个方法

public class Handler {
     public void dispatchMessage(@NonNull Message msg) {
            ...
            handleMessage(msg); // 最终会回到这个方法,
            ...
    
    }
}

以上就是整个handler工作的基本的流程了。

总结

handler创建的时候同时会获取创建该handler的A线程所对应的looper对象,并调用loop方法不断循环从looper的messagequeue中取出消息,当handler在B线程里面发送消息的时候,会把message加入该handler的looper所对应的唯一messagequeue队列中去,前面说到的loop方法会回调A线程创建的handler的handlemessage方法,由此完成了message从子线程到主线程的切换。

msg
msg
对应一个Looper
对应一个MessageQueue
loop方法
msg
获取最新的消息msg
msg
Handler
sendMessageAtTime
enqueueMessage方法插入队列
Looper
MessageQueue
prepare
不断循环从messagequeue获取消息
handleMessage
相关标签: android android