Handler源码解析

Handler 源码解析

序言:上一篇文章介绍了handler的用法,这次来分析一下handler的实现原理.网上有很多文章对handler 的源码进行分析,我也看了很多,从中收益匪浅,但是很多文章,写的并不能深入我心,所以,我要写一篇最能深的我心的文章.因为自己的才是最好的.哈哈哈哈
在这里插入图片描述

一,Handler流程图

首先我们通过一张handler的流程图,来描述一下Message传递的情况:
在这里插入图片描述
图中的箭头指向,代表Message的走向.
上边一共涉及到四个类,分别是
在这里插入图片描述

  • Message : 消息,线程间通讯的数据单元
  • MessageQueue : 消息队列,先进先出
  • Handler : 处理器,Message发送,和Message最终执行的地方
  • Looper : 循环器

传递Message的过程中,还会涉及到其他的几个类,我们提到时在详细说明

我将Handler分为两大模块来讲述,1,初始化 .2.消息传递过程

二.初始化

初始化就是做消息发送前的准备工作,我的在使用的时候,会先初始化一个Handler

1.Handler初始化

上一篇文章介绍到handler初始化的两种方式
方式一:

Handler sHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
            @Override
            public boolean handleMessage(Message message) {
                switch (message.what) {
                    case MSG_SHOW:
                        ((YJSnackbar) message.obj).showView();
                        return true;
                    case MSG_DISMISS:
                        ((YJSnackbar) message.obj).hideView(message.arg1);
                        return true;
                }
                return false;
            }
        });

方式二:

Handler mHandler = new Handler()

两种初始化方式对应两大类发送消息的方法
方式一 ->sendMessage()
方式二 -> postMessage()
我们现在就来通过源码分析一下,Handler在初始化的时候,都做了些什么

Handler构造函数

1.先看Handler的构造函数
handler构造函数
ps:图是我纯手工码的,效果可能不太完美,大家凑合看吧
从途中我们可以看出,Handler一共有七个构造函数,最终调用到两个,两个构造函数的不同点在于Looper
我们来看看两个构造函数中,都做了什么
第一个:不带Looper 的 Handler(Callback callback, boolean async)

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;
        mCallback = callback;
        mAsynchronous = async;
    }

因为他不带Looper 所以,通过Looper.myLooper()方法获取mLooper.如果mLooper==null,直接抛异常
我们再来看看Looper.myLooper();做了写些什么

	/**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

这个是Looper类中的一个静态方法,通过sThreadLocal.get()来获取Looper
这个mThreadLocal又是什么呢

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

Looper中的一个静态 final变量.
这里我简单的介绍一下ThreadLocad这个类,不然没办法进行后续步骤.

Threadlocal

它是java.lang包里的一个类,代码不多,700+行,想探索的小伙伴,可以自己去看一下代码.
ThreadLocal主要功能是:

/**
 * This class provides thread-local variables.  These variables differ from
 * their normal counterparts in that each thread that accesses one (via its
 * {@code get} or {@code set} method) has its own, independently initialized
 * copy of the variable.  {@code ThreadLocal} instances are typically private
 * static fields in classes that wish to associate state with a thread (e.g.,
 * a user ID or Transaction ID).
 *
 * <p>For example, the class below generates unique identifiers local to each
 * thread.
 * A thread's id is assigned the first time it invokes {@code ThreadId.get()}
 * and remains unchanged on subsequent calls.
 
 * </pre>
 * <p>Each thread holds an implicit reference to its copy of a thread-local
 * variable as long as the thread is alive and the {@code ThreadLocal}
 * instance is accessible; after a thread goes away, all of its copies of
 * thread-local instances are subject to garbage collection (unless other
 * references to these copies exist).
 */

存储在指定线程的数据的存储类,只能在指定的线程中获取.实现了线程隔离.

在这里插入图片描述
很多小伙伴看完心中默念:你他喵的这说的是个鬼啊
别着急,我有法宝,让大家秒懂他的含义,秒???.是的秒懂
在这里插入图片描述

static ThreadLocal<Integer> mThreadLocal = new ThreadLocal<Integer>();
public static void main(String[] args) {
        mThreadLocal.set(1);
        System.out.println(""+mThreadLocal.get());

        new Thread("线程1") {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().toString());
                //线程1中get,输出为null
                System.out.println(""+mThreadLocal.get());
            }
        }.start();

        new Thread("线程2") {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().toString());
                //先set在get
                mThreadLocal.set(2);
                System.out.println("get()的x="+mThreadLocal.get());
                int x = mThreadLocal.get();
                mThreadLocal.set(++x);
                System.out.println("set()后的x="+mThreadLocal.get());
            }
        }.start();

    }

输出的结果

1
Thread[线程1,5,main]
null
Thread[线程2,5,main]
get()的x=2
set()后的x=3

可以看出,在不同线程中,Threadloacl.get()的结果是不一样的
主线程中:set=1,所以get = 1
线程1中:没有set,所以get = null
线程2中:set=2, 所以get = 2,在重新set=3 ,所以get=3
我们进入到set()方法中去看一下

/**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {
        Thread t = Thread.currentThread();
        //从当前线程中获取ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //如果map不为空,把value设置给map ,他的key.= this ,就是当前的这个Threadlocal
        if (map != null)
            map.set(this, value);
        else
        	//如果map为空,创建
            createMap(t, value);
    }
    //初始化ThreadLocalMap ,并且赋值给前线程的threadLocals
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

ThreadLocalMap是ThreadLocal的静态内部类,里边有一个私有变量叫

Entry[] table

而Entry又是ThreadLocalMap 中的一个静态内部类,继承WeakReference的 弱引用

		static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

里边用threadlocal 作为key,存储Object 的value,这就是上一步Threadlocal中用this作为key的原因

在ThreadLocalMap初始化的时候,初始化Entry[] table ,table是个数组,值是16, 也就是说,Threadlocal中,最多存16个数据

private static final int INITIAL_CAPACITY = 16;
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }

终于说完了Threadlocal,我们重新回到Handler初始化
当handler发现,当前线程中没有Looper,完蛋,直接抛出异常:“Can’t create handler inside thread that has not called Looper.prepare()”);
小伙伴们是不是对这个异常有几分眼熟,是不是当初自己刚用handler时常常出现的一个bug?
也有许多小伙伴们奇怪,这个Looper.prepare()是什么鬼,我在主线程创建Handler时,并没有调用他,为什么也不会抛异常呢?
关于Looper的,小伙伴们别着急,他是Handler机制的核心,我们先跳过他把Handler初始化讲完,在详细的讲解一下
说完Looper的判断接下来说后边的代码

		mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;

顺道也把第二种Handler初始化的方式说了

/**
     * Use the provided {@link Looper} instead of the default one and take a callback
     * interface in which to handle messages.  Also set whether the handler
     * should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * 这个注释很重要,
     * @param looper The looper, must not be null.
     * @param callback The callback interface in which to handle messages, or null.
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
public Handler(Looper looper, Callback callback, boolean async) {
		//注意了,looper不能为空,不能
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

这就很简单了,赋值给Handler中变量.
Looper就是上文提到的循环器
mQueue就是消息队列
Callback mCallBack 是Handler中的一个接口,有一个回调方法

	public interface Callback {
        public boolean handleMessage(Message msg);
    }

总结一下Handler的初始化
在这里插入图片描述
Handler初始化讲解结束,然后将Looper.
今天先写到这里,晚上回去估计没有的更新,明天在写吧

Looper初始化

咱们书接上回,来聊聊Looper的初始化都做了什么
我们打开Looper类,看他的构造函数

    final MessageQueue mQueue;
    final Thread mThread;

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

有且仅有一个私有的构造函数,做了两个事情

  • 1:初始化了一个MessageQueue,赋值给mQueue,Handler初始化的时候,就是获取的这个MessageQueue,
  • 2: 把当前线程,赋值给mThread

这两个变量都是final 一经赋值,不在改变
构造函数是私有的,那肯定有其他的public方法对外开放啊,可是并没有直接的public方法初始化Looper.

/**
*唯一的初始化Looper的方法,也是私有静态的
*/
private static void prepare(boolean quitAllowed) {
		/*Looper有且只能有一个*/
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        //将初始化的Looper  set给sThreadLocal
        sThreadLocal.set(new Looper(quitAllowed));
    }

这个方法在两个地方被调用,
第一个:

/**
这个方法是不是很眼熟,就是Handler初始化的时候,如果Looper.myLooper()等于空时,报的异常,
Can't create handler inside thread that has not called Looper.prepare()
*/
public static void prepare() {
        prepare(true);
    }

第二个:不能直接用到的,我们在项目中,一般不要用到这方法.

//是一个私有静态对象,
private static Looper sMainLooper;  // guarded by Looper.class

	public static void prepareMainLooper() {
        prepare(false);
        /**
        同步锁,当变量sMainLooper!=null时,抛出一个异常.
        所以在Activity中,如果我们直接使用这个方法就会抛出异常导致程序崩溃,有同学肯定会奇怪,为什么会抛异常,我明明没有调用过,为什么sMainLooper却有值?因为我们的ActivityThread类中已经调用过了,
        */
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    
    /**
    sMainLooper只有一个get方法,没有set,只有在prepareMainLooper时设置.
    返回application的主Looper,它存在与主线程.
     * Returns the application's main looper, which lives in the main thread of the application.
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }
ActivityThread

Looper的初始化基本介绍完了,只留下一个小问题,为什么我们在项目中不能调用prepareMainLooper,还有Handler在主线程初始化时,为什么不用调用Looper的任何一个初始化方法?
小伙伴们可能会喷我:你个傻嗨,这是两个问题.
委屈巴巴,其实这是同一个问题.
答案就在ActivityThread类的main方法中,下边是main方法中的代码,我全部贴上了,

/**
Android也是用java写的,所以肯定也是有main方法的,
这个就是Android程序的起点,Main方法.
如果以后再有人问你,Android中是不是有main方法,就大胆肯定的告诉他,
有!!!
它里边做了很多东西,我们只找关于Handler初始化的代码,找到Looper.prepareMainLooper();
*/
    public static void main(String[] args) {
        //.......多余的代码省略吧
		/**
		初始化主线程的Looper,看到了没在这里初始化的主线程的Looper,所以
		1>我们在Activity,Service,Broadcast中使用Handler		是不需要初始化的,
		2>我们在Android程序中也是不能使用Looper.prepareMainLooper(),因为在程序的Main方法中已经调用过了.
		我没有骗你们吧 ,这是同一个问题.
		*/
        Looper.prepareMainLooper();

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

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        //这里有一个关于Looper的代码,启动loop开启循环,
        Looper.loop();

		//然后,直接抛异常,小伙伴看了这句是不是异常懵逼,直接让程序崩溃?这是什么鬼代码,你没有眼花,也不是google的工程师脑袋抽了,这里涉及到另外一个知识点,我们只需要记住,
		Android程序都是在Looper.loop()中.比如Activity以及他的生命周期,
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

loop:先简单的说一下,等到消息处理时,我们在详细介绍.
loop是一个无线循环,从MessageQueue.next中,获取Message,如果有Message,就处理,没有消息就休眠
我贴出代码,是希望有兴趣的小伙伴可以看看,Android中神秘的mian方法,到底做了些神秘,如果没兴趣,就直接看我中文注释的解释就好了.另外在最后补充一点:
sMainThreadHandler是H extends Handler,里边是用来处理很多我们非常熟悉的LAUNCH_ACTIVITY,
生命周期以及一些其他的消息的
最后,对Looper做个总结:
在这里插入图片描述
ActivityThread 中main方法关于Handler的地方:
在这里插入图片描述

MessageQueue初始化

非常简单两个变量的赋值

	MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }

MessageQueue是Looper中的变量,Looper线程中唯一的存在,那么等同于一个线程中,也是有且只能有一个MessageQueue.
有一个变量Message mMessage
在这里插入图片描述

Message

最后一个初始化的对象,就是我们的消息Message了,Handler机制的最终目的是什么,传递消息啊,而Message就是我们穿的消息单元.只有有了Message,我们才能把消息传递到制定的线程
Message是一个链表,

1:Message可以直接new 因为构造函数是公有的无参构造
2:obtain() :共7个obtain方法,主要是传参不同,最终都是调用无参的obtiain()

/**这几个变量很重要*/
/*package*/ Handler target;//发送消息的Handler

 /*package*/ Runnable callback;//处理消息的回调
地址域 ,指向下一个数据域
/*package*/ Message next;//消息链表,指向下一个Message

private static Message sPool;//可复用的Message链表
//sPool链表的最大值50个
private static final int MAX_POOL_SIZE = 50;

/**一个消息队列中消息复用的方法*/
public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;//将链表头取出来,用于返回值,重新使用
                sPool = m.next;		//将sPool指向链表的第二Message
                m.next = null;			//清空用于返回的Message的指向
                m.flags = 0; 			// clear in-use flag
                sPoolSize--;				//将pool的size减1
                return m;
            }
        }
        return new Message();
    }

mPool复用Message池中的数据是什么时候添加的呢,在Message的recycle()方法中

    public void recycle() {
        if (isInUse()) {
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        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) {//如果没有超过最大值50
                next = sPool;	//将next指向sPool
                sPool = this;	//将sPool指向this(Message).把this作为链表的头.
                sPoolSize++;	//size+1
            }
        }
    }

然后呢,我们最Message做个总结:
在这里插入图片描述
所有的准备工作终于做完了,可以愉快的发送消息了吗?
不还不能,因为有一个非常重要的步骤还没有启动,那就是Looper.loop

Looper.loop()

大家是否还记得,前边ActivityThread类中的main()方法中,就有这么一句话?
这个方法的做用就是:开启循环器的循环,是必不可少的一部,非常之重要,视为核心
…如果MessageQueue中有Message,处理Message,
如果没有就休眠.
//引入一个新的问题,为什么,主线程中的for循环一直在,却不会ANR

    public static void loop() {
        final Looper me = myLooper();//获取当前线程的Looper
        if (me == null) {//Looper为空,抛出异常
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;//获取Looper中的变量MessageQueue
        //........省略部分代码
        for (;;) {//死循环开启,
            Message msg = queue.next(); // might block
            if (msg == null) { //如果没有消息,return
                // No message indicates that the message queue is quitting.
                return;
            }

            //如果有消息处理消息,先不详细说,这里只说开启循环
        }
    }

流程大致如下图:
在这里插入图片描述
初始化工作全部完成:总结一下初始化流程,共分为三部

  • 第一步:创建Looper,同时创建MessageQueue
  • 第二步:创建Handler
  • 第三步:启动Looper.loop()

第二,第三步顺序可颠倒.

三.发送消息

通过handler发送消息的方法,在上一篇Handler使用方法中,有详细介绍,这里在重新讲一遍.
在这里插入图片描述
上一篇文章中用的思维导图,这次用流程图,感觉会更清晰一点.
粗略讲解一下三类发送方法

  • 第一类 :sendEmpty方法,共有三个方法,都有一个int what作为参数,在消息处理时,根据what处理消息,初始化一个Message,what赋值给Message.what,然后到sendMessage类方法中,
  • 第二类:post方法,共有五种方法,参数都为Runable,然后通过getPostMessage()方法,初始化Message,并且把参数Ruanable赋值给Message.callback
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

最后调用sendMessage方法

  • 第三类,sendMessage方法,共有四个方法.

最后统一调用私有方法enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
  • 1.将当前handler赋值给Message,target,
  • 2.这个设值我们先跳过
  • 3.将消息msg加入消息队列queue,并返回结果

在MessageQueue的enqueueMessage(Message msg, long when)方法中又是怎么添加消息到链表呢?

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {//判断,如果msg中的Handler为空,直接抛异常,所以,我们发送的msg,必须有target
            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,将此msg加入到Message的缓存池mPool中
                msg.recycle();
                return false;//返回添加队列结果为fasle
            }

            msg.markInUse();//标记msg为正在使用中
            msg.when = when;//赋值为when
            Message p = mMessages;//mMessage为链表的头
            boolean needWake;//是否需要唤醒Looper中的无线循环,
            if (p == null || when == 0 || when < p.when) {//如果,链表为空,或者,不需要1,延迟2.循环,或者msg的延时小于mMessage的延时,
                // New head, wake up the event queue if blocked.
                msg.next = p;//将msg的next,指向p
                mMessages = msg;//然后将msg设置为链表头,相当于插入msg到链表头,
                needWake = mBlocked;//需要唤醒looper中的循环
            } else {//其他情况,(链表不为空,需要延迟执行的msg)
                // 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();//是否需要唤醒looper的循环
                Message prev;	//将msg插入到链表中.
                for (;;) {//1:循环,根据when,判断出msg需要插入链表的位置
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;//设置,不需要唤醒,
                    }
                }
                //2.插入链表
                msg.next = p; // invariant: p == prev.next 
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {//如果需要唤醒Looper循环
                nativeWake(mPtr);//native方法唤醒,这里就不过多介绍了.
            }
        }
        return true;//返回添加msg到queue的结果为true
    }

下边是nativeWake(mPtr)的JNI方法

static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->wake(); 【3】
}

void NativeMessageQueue::wake() {
    mLooper->wake();  【4】
}

void Looper::wake() {
    uint64_t inc = 1;
    // 向管道mWakeEventFd写入字符1
    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
    if (nWrite != sizeof(uint64_t)) {
        if (errno != EAGAIN) {
            ALOGW("Could not write wake signal, errno=%d", errno);
        }
    }
}

发送消息,到此为止.总结:如下图,实在不知道用流程图更加清晰还是用思维图更清晰,就用思维图吧,大家如果觉得不够清晰,请流言,我会在重新做个流程图的.
在这里插入图片描述

四.处理消息

消息发送之后到底是怎么处理的呢?怎么把线程切换到了接收线程来处理消息呢?
这个过程有JNI代码在里边,比如MessageQueue中有提到,如果消息需要立即执行,nativeWake()方法唤醒,往信道里写入数据.
JNI层的代码,我们这篇文章不深入讨论,只是大致介绍一下流程.
Looper.loop()方法,我们已经说过是开启无线循环,在看一遍loop()方法吧各位大佬,这次也是删减过得,无关代码我都会清除掉,想看完整的代码就自行去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 (;;) {//无线循环,
            Message msg = queue.next(); // might block
            /**
            如果消息等于空.直接返回.说好的阻塞呢?说好的休眠呢?直接return了?其实阻塞代码在上一步queue.next()中
            */
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));//开始追踪
            }
            //获取系统启动到现在的时间,不包括息屏状态的时间
            final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            final long end;
            try {
            //调用msg中的target ,target是发送msg的Handler,dispathchMessage处理消息
                msg.target.dispatchMessage(msg);
                //结束时间.处理消息结束的的时间搓
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);//结束追踪
                }
            }

            //msg释放回收等待下次利用
            msg.recycleUnchecked();
        }
    }

MessageQueue 的next方法,都做了什么,才能取到消息链表中的Message呢?

Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr; //在native方法中使用,
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();//又是一个native方法,
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);//真正的阻塞休眠代码,

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                //获取系统启动时间
                final long now = SystemClock.uptimeMillis();
                //消息链表中的前一个消息
                Message prevMsg = null;
                //消息链表的第一个消息
                Message msg = mMessages;
                if (msg != null && msg.target == null) {//消息不为空,消息的target为空
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                    //将链表中的此msg移除,移除的msg保存在prevMsg
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {//msg不为空,
                    if (now < msg.when) {//msg的延迟执行时间,大于现在时间now
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        //下一条消息还没有准备好。设置一个超时时间当它准备好时唤醒。
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);//进入等待,
                    } else { //否则
                        // Got a message.得到一条可执行的消息
                        mBlocked = false;
                        if (prevMsg != null) {//如果有被移除队列的没有target的消息,将队列置于pervMsg后
                            prevMsg.next = msg.next;
                        } else {//否则,将消息链表的表头,后移一位
                            mMessages = msg.next;
                        }
                        msg.next = null;//清除msg的地址域指向
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();//标记msg正在使用中
                        return msg;	//将msg返回.
                    }
                } else {//如果msg==null,没有可执行的消息
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }
    }

我带大家看一下nativePollOnce方法里,大致做了什么,以下关于nativePollOnce的内容,来源于于Handler的native层详情
调取信息的调取链如下图:
调取信息链

static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, jlong ptr, jint timeoutMillis) {
    //将Java层传递下来的mPtr转换为nativeMessageQueue
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->pollOnce(env, obj, timeoutMillis); 【3】
}

这里感叹一下,你如果只在java层理解Handler,是无论如何都不能100%完全理解的,循环休眠和时间计算,延迟执行的代码,都在native层.java要想精通,还是要C++精通才行啊.
queue,next()介绍完了,我们获取到了msg 或者在等待获取msg,直到我们获取到msg
我们在回到Looper.loop方法中,

		try {
		//最终执行代码,用msg中的target调用dispatchMessage()来处理消息.
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }

我们看一下Handler中的dispatchMessage方法

/**
     * Handle system messages here.
     * Handler机制在这里处理消息
     */
    public void dispatchMessage(Message msg) {
    	/**
		 //如果msg中的变量callback不为空,callback是一个Runable,通过post方法发送的消息都在这里
		 执行
		*/
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
        	/**
        	mCallback是Handler中的变量Callback,Callback是一个Handler中的接口
        	然后需要在Handler初始化的时候传入,但是两个传入Callback参数的
        	构造函数,是hide的
        	*/
            if (mCallback != null) {//当mCallback不为空的时候,
                if (mCallback.handleMessage(msg)) {//如果执行成功,直接返回
                    return;
                }
            }
            //执行我们重写的handleMessage方法.
            handleMessage(msg);
        }
    }

第一种处理消息的方法:

    private static void handleCallback(Message message) {
	    //	执行Runable的run方法
        message.callback.run();
    }

最后总结一下消息处理的过程
消息处理
其中的queue.next方法的流程为:
在这里插入图片描述
至此,Handler机制源码解析全部结束,本文是我纯手工打造,除了涉及到的两三个native方法为参考,文中也附上了链接.非常感谢各位的耐心阅读.如有错误之处,请不吝赐教,我一定会及时改正,虚心求教.

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值