Android Handler原理源码全解析

前面已经写过handler的使用方法了 -> Android Handler全使用,本篇将详解handler机制原理和源码。

Message

线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。使用Message的arg1和arg2便可携带int数据,使用obj便可携带Object类型数据。

Handler

消息的处理者。在子线程调用sendMessage方法发送消息对象Message,而发送的消息经过一系列地辗转之后最终会被传递到Handler的handleMessage方法中,完成消息对象Message的处理。

MessageQueue

消息队列。只存放所有通过Handler发送过来的Message消息对象。这部分消息会一直存放于消息队列当中,等待被处理。

每个线程中只会有一个MessageQueue对象。

MessageQueue中有两个比较重要的方法,一个是enqueueMessage方法,一个是next方法。enqueueMessage方法用于将一个Message放入到消息队列MessageQueue中,next方法是从消息队列MessageQueue中阻塞式地取出一个Message。

Looper

MessageQueue的管家。每个线程只有一个Looper对象。调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当MesssageQueue中存在一条消息,Looper就会将这条消息取出,并将它传递到Handler的handleMessage()方法中。

注意:

  • 一个线程只有一个Looper,但可以有多个处理者Handler
  • 一个Looper可绑定多个处理者Handler,但一个处理者Handler 只能绑定一个 Looper

 

工作流程图

Android Handler原理源码全解析_第1张图片

 

源码解析

1、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 " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
}

由上可知,创建handler时

1)会自动关联线程中的Looper对象(绑定线程),若线程无Looper对象则抛出异常。

若线程中无法创建Looper对象,则也无法创建Handler对象,因此若需要在子线程中创建Handler对象,则需先创建Looper对象。

2)绑定MessageQueue对象,至此,handler对象关联上了 Looper对象中的MessageQueue

那么这里的Looper对象怎么来的呢,什么时候创建的?

2、Looper

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

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

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 void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

看Looper构造方法,可知Looper创建一个对象时就自动创建一个当前线程的MessageQueue对象。

从Lopper.prepare()方法可看到,为当前线程创建Looper对象,存放在ThreadLocal变量中。当我们需要在子线程中创建Looper时便需要调用该方法(在子线程若不手动创建Looper对象 则无法生成Handler对象)

注意:这里有个方法 prepareMainLooper,为主线程创建Looper对象。该方法在主线程(UI线程)创建时自动调用:

// ActivityThread类
public static void main(String[] args) {
            ...

             // 1. 为主线程创建1个Looper对象,同时生成1个消息队列对象(MessageQueue)            
            Looper.prepareMainLooper(); 
                      
            // 2. 创建主线程
            ActivityThread thread = new ActivityThread(); 
            
            // 3. 自动开启 消息循环
            Looper.loop();             

}

即主线程的Looper对象自动生成,无需手动生成。

生成Looper & MessageQueue对象后,则会自动进入消息循环:Looper.loop(),源码如下:

 public static void loop() {
            ...      
    
            final Looper me = myLooper();//返回sThreadLocal存储的Looper实例
            if (me == null) {
                throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
            }           
            
            // 获取Looper实例中的消息队列对象(MessageQueue)
            final MessageQueue queue = me.mQueue;            

            // 消息循环
            for (;;) {                       
                Message msg = queue.next(); // 取出消息
                // 若取出的消息为空,则线程阻塞
                if (msg == null) {
                    return;
                }          

                // 派发消息到对应的Handler,把消息Message派发给消息对象msg的target属性
                // target属性实际是1个handler对象
                msg.target.dispatchMessage(msg);           

                // 释放消息占据的资源
                msg.recycle();
            }
    }

注意,这里两个主要操作:取出队列中的消息对象--queue.next(),分发消息给handler--dispatchMessage(msg);

看一下两个方法源码:

Message next() {
        ...
        // 该参数用于确定消息队列中是否还有消息
        // 从而决定消息队列应处于出队消息状态 or 等待状态
        int nextPollTimeoutMillis = 0;

        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

        // nativePollOnce方法在native层,若是nextPollTimeoutMillis为-1,此时消息队列处于等待状态 
        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
     
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;

            // 出队消息,即 从消息队列中取出消息:按创建Message对象的时间顺序
            if (msg != null) {
                if (now < msg.when) {
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // 取出了消息
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {

                // 若消息队列中已无消息,则将nextPollTimeoutMillis参数设为-1
                // 下次循环时,消息队列则处于等待状态
                nextPollTimeoutMillis = -1;
            }
            ...
        }
           ...
       }
}
public void dispatchMessage(Message msg) {
    // 若msg.callback属性不为空,则代表使用了post(Runnable r)发送消息
    // 则执行handleCallback(msg),即回调Runnable对象里run()方法
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }

            // 若msg.callback属性为空,则代表使用了sendMessage(Message msg)发送消息
            // 则执行handleMessage(msg),即回调复写的handleMessage(msg) 
            handleMessage(msg);
        }
    }

可以看到,取出dispatchMessage()执行后就回到我们熟悉的run方法或者handleMessage方法了!

3、Message

那么Message对象是怎么创建的呢,在上节handler的使用中,我们已经说明,是通过obtain方法创建的。

public static Message obtain() {
        // Message内部维护了1个Message池,用于Message消息对象的复用       
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; 
                sPoolSize--;
                return m;
            }           
        }
        // 若池内无消息对象可复用,则还是用关键字new创建
        return new Message();
}

当然,我们也可以new一个message,不过更推荐使用obtain()创建消息对象,避免每次都使用new重新分配内存.

4、工作线程发送消息至消息队列

我们在工作线程中,发送了消息,

当使用方式为:mHandler.sendMessage(msg),发生了什么呢?

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


public final boolean sendMessageDelayed(Message msg, long delayMillis){
    if (delayMillis < 0) {
          delayMillis = 0;
    }

    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

        
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    // 获取对应的消息队列对象(MessageQueue)
    MessageQueue queue = mQueue;

    // 调用enqueueMessage方法
    return enqueueMessage(queue, msg, uptimeMillis);
}


private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {

     // 将msg.target赋值为this,即把当前的Handler实例对象作为msg的target属性
     // 因此,在loop()循环中才是msg.target执行dispatchMessage(msg)方法
     msg.target = this; 
      
     // 调用消息队列的enqueueMessage(),Handler发送的消息,最终是保存到消息队列
     return queue.enqueueMessage(msg, uptimeMillis);
}

       
//将消息 根据时间 放入到消息队列中(Message ->> MessageQueue)
//采用单链表实现:提高插入消息、删除消息的效率
boolean enqueueMessage(Message msg, long when) {
        ...
        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;

             // 若有,则根据 消息(Message)创建的时间插入到队列中
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                 }

                 msg.next = p; 
                 prev.next = msg;
             }
            if (needWake) {
               nativeWake(mPtr);
            }
        }
        return true;
}

enqueueMessage将消息对象message插入到队列之后,随着Looper对象的无限消息循环,不断从消息队列中取出Handler发送的消息,并且分发到对应Handler,最终回调Handler.handleMessage()处理消息。

当选择post方式发送消息时,又是怎样的呢?

实际上最终调用方式是一样的:

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

private static Message getPostMessage(Runnable r) {
    // 系统帮我们自动创建一个message对象
    Message m = Message.obtain();
    // 将 Runable对象 赋值给消息对象(message)的callback属性
    m.callback = r;
    return m;
}

public final boolean sendMessageDelayed(Message msg, long delayMillis){
    if (delayMillis < 0) {
       delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

后面的就和上面sendMessage方式分析的一样的了。

好了,原理和源码都已讲完,下一篇我将根据这篇内容,尝试手写一套handler机制!敬请期待!

你可能感兴趣的:(Android,源码)