Android音信处理机制,MessageQueue源码剖析

MessageQueue

Android是消息使得的,完成新闻使得有多少个成分:

1.变量

    private final boolean mQuitAllowed;//表示MessageQueue是否允许退出
    @SuppressWarnings("unused")
    private long mPtr; //mPtr是native代码相关的

    Message mMessages; //表示消息队列的头Head
    private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
    private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
    private IdleHandler[] mPendingIdleHandlers;
    private boolean mQuitting;

    // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
    private boolean mBlocked;

    // The next barrier token.
    // Barriers are indicated by messages with a null target whose arg1 field carries the token.
    private int mNextBarrierToken; 

mQuitAllowed表示MessageQueue是不是允许退出,系统创造的UI线程的MessageQueue是分裂意的,别的顾客端代码创设的都以同意的;

mPtr是native代码相关的,指向C/C++代码中的某个对象(指针卡塔尔国,其余部分nativeXXX()相关的函数本文暂不做深入分析;

mMessages表示新闻队列的头Head;

mIdleHandlers是IdldHandler接口的ArrayList,
mPendingIdleHandlers是数组版本,在后头的代码中会将ArrayList的开始和结果拷贝到它里面;

mQuitting表示近来队列是不是处在正在退出状态;

mBlocked表示next()调用是不是被block在timeout不为0的pollOnce上;

mNextBarrierToken表示下多个barrier
token,barrier用target==null, arg1==token的Message对象表示;

1、Message:音讯,在这之中蕴藏了信息ID,新闻管理对象甚至管理的数量等,由MessageQueue统一列队,终由Handler管理

IdleHandler callback接口:

public static interface IdleHandler {
        /**
         * Called when the message queue has run out of messages and will now
         * wait for more.  Return true to keep your idle handler active, false
         * to have it removed.  This may be called if there are still messages
         * pending in the queue, but they are all scheduled to be dispatched
         * after the current time.
         */
        boolean queueIdle();
    }
public void addIdleHandler(IdleHandler handler) {
        if (handler == null) {
            throw new NullPointerException("Can't add a null IdleHandler");
        }
        synchronized (this) {
            mIdleHandlers.add(handler);
        }
    }
 public void removeIdleHandler(IdleHandler handler) {
        synchronized (this) {
            mIdleHandlers.remove(handler);
        } 

IdleHandler接口表示当MessageQueue发掘脚下尚未越来越多音信能够管理的时候则顺便干点别的事情的callback函数(即只要发掘idle了,

那就找点别的事干卡塔 尔(英语:State of Qatar)。callback函数有个boolean的重临值,表示是或不是keep。要是回到false,则它会在调用达成之后从mIdleHandlers

中移除。这里让我们来看多个现实的例证(完毕卡塔 尔(阿拉伯语:قطر‎,ActivityThread.java里的一个里面类,代码如下:

final class GcIdler implements MessageQueue.IdleHandler {
        @Override
        public final boolean queueIdle() {
            doGcIfNeeded();
            return false;
        }
    } 

那是二个gc相关的IdleHandler,即只要未有越来越多的音讯能够拍卖就能够抽空doGcIfNeeded(),最终回来false表示不保留在mIdleHandlers

中,即用叁次就扔了,只进行一回。

2、管理者,担负Message的出殡和下葬及处理。使用Handler时,供给得以达成handleMessage(Message

MQ的构造方法:在Looper中正是调用的那一个构造方法。

MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;  //true是允许推出
        mPtr = nativeInit(); //这是一个本地方法
    }

MQ的构造方法轻巧的调用了nativeInit()来进行带头化,那是贰个jni方法,也正是说,或者是在JNI层维持了它这一个音讯队列的对象。在message中有无数native方法,能够看出message是比较底层的二个类。

接下去看MessageQueue的中坚措施,next()方法,如下:

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;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            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) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // 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) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }

率先起先化2个接下去要用到的变量,紧接着步入无限for循环中,其某次循环主要做如此几件专门的职业:

  1. 如果nextPollTimeoutMillis !=
    0的话,调用Binder.flushPendingCommands();

  2. 调用nativePollOnce(mPtr,
    nextPollTimeoutMillis);

3.
跻身贰个大的一块儿块,尝试获得贰个得以管理的音讯,具体做法是,记录当前时刻now,伊始化变量prevMsg为null,msg为mMessges;

假若msg是二个sync
barrier新闻,则直接奔着下一个asynchronous音讯(那中间的富有联合新闻会被这次循环忽视,也便是说遭受这种状态,

next方法会从找到的异步音信的职务上马尝试获得二个能够拍卖的音讯并回到卡塔 尔(阿拉伯语:قطر‎,相同的时候更新prevMsg,msg的值;

4.当退出此do…while循环的时候msg只怕为空(走到行列尾了卡塔尔国,或许成功找到了贰个这么的(异步卡塔尔国音信。

msg)方法来对一定的Message进行处理,比如更新UI等。

5.假设是到队尾了即msg==null,则象征没更加多的音信了,设置nextPollTimeoutMillis

-1;否则当now<msg.when(msg的时光尚未到卡塔尔国,设置贰个靠边的等待时间,即调用

nextPollTimeoutMillis = (int)
Math.min(msg.when – now, Integer.MAX_VALUE);

6.当msg到了该管理的日子了,相当于说大家找到了那样二个新闻可以回去了,设置mBlocked为false,将msg从mMessages队列中收取来(相同单链表的去除操作卡塔 尔(英语:State of Qatar),并执行

msg.next=null、msg.markInUse(),返回msg。

7.倘若到这一步了尚未return的话,那表明还向来不得以拍卖的音信,检查下队列是或不是必要退出了,假设是实行dispose(),再次回到null。当Looper的loop方法来看null的message的时候会退出loop。

8.接下来既然没消息能够拍卖,那就该处理IdleHandler了。假若pendingIdleHandlerCount小于0(注意其在首先次步入for循环是被初阶化为-1卡塔尔且没更多的音讯供给管理,设置pendingIdleHandlerCount=mIdleHandlers.size();

9.倘诺pendingIdleHandlerCount依旧<=0的话,表示尚无idle
handler须求实行,

设置mBlocked为true,接着步入后一次巡回。

10.接下来正是依据mIdleHandlers来最早化mPendingIdleHandlers。退出联合块后大家就剩下最后风流倜傥件事了,那就是run
Idle
handlers。二个for循环用来做那就事情,在循环内要是IdleHandler没须求保留,则会从mIdleHandlers中移除。

11.
最后重新初始化pendingIdleHandlerCount为0(也正是4只会在率先次巡回的时候实施一遍卡塔 尔(英语:State of Qatar),将nextPollTimeoutMillis设为0,因为当我们在

施行4的时候,新的Message大概曾经来到了,所以大家供给马上开端(无需拭目以俟卡塔尔后一次循环来检查。

**地点相当长,不难点说正是:next方法抽出下二个Message(从底部取卡塔尔,若无Message能够管理,就能够拍卖下IdleHandler。

3、MessageQueue:新闻队列,用来贮存在Handler发送过来的信息,并依照FIFO准绳实践。当然,贮存Message并不是实际意义的保存,而是将Message以链表的措施串联起来的,等待Looper的抽出。

看完了next()方法,接下去大家来看enqueue()方法:

boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            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.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            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 {
                // 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();
                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;
    } 

在后边介绍Handler的时候,能够见到,大多跟message(满含runnable卡塔尔相关的操作,最后都delegate给了MessageQueue的enqueue方法。

和其余措施雷同,在enqueue此前,也都以对参数msg的反省,举个例子msg即便在接纳中,只怕msg的target是null,都会抛出AndroidRuntimeException,举行完条件检查后,会进去真正的拍卖逻辑。接下来的操作看似在一张单链表中插入一个要素:步向同步块

1.
只要此行列处周振天在退出的处境则不能够在往里入队了,不可能插入成分了,在此种状态下会抛出RuntimeException,然后return
false,

表示战败了;

2.
接下去表示队列的状态ok,设置msg的when字段,一时变量p指向队列头;(须求的开首化,希图干活卡塔 尔(阿拉伯语:قطر‎

3.
假若队列是空的或when==0或when<p.when,也便是说要插入的那些message应该在率先个职分也正是队首,那么它将是新的Head,将它和原本的队列连接起来;

4.
再不插入将发出在队列中间的某部地方(有相当大希望是队尾),将msg插在首先个p的先头,p满足那些准则(p
== null || when < p.when)。

末段退出联合块,再次回到true,表示操作(入队卡塔尔国成功。

**messageQueue中的成分是按序定时间顺序插入的(先推行的在前卡塔尔国。

4、Looper:音讯泵,不断地从MessageQueue中收取Message实践。由此,二个MessageQueue须要一个Looper。

removeMessages():

进而大家来看3个像样的removeMessages()方法,

 void removeMessages(Handler h, int what, Object object) {
        if (h == null) {
            return;
        }

        synchronized (this) {
            Message p = mMessages;

            // Remove all messages at front.
            while (p != null && p.target == h && p.what == what
                   && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }

            // Remove all messages after front.
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && n.what == what
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }

    void removeMessages(Handler h, Runnable r, Object object) {
        if (h == null || r == null) {
            return;
        }

        synchronized (this) {
            Message p = mMessages;

            // Remove all messages at front.
            while (p != null && p.target == h && p.callback == r
                   && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }

            // Remove all messages after front.
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && n.callback == r
                        && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }

    void removeCallbacksAndMessages(Handler h, Object object) {
        if (h == null) {
            return;
        }

        synchronized (this) {
            Message p = mMessages;

            // Remove all messages at front.
            while (p != null && p.target == h
                    && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }

            // Remove all messages after front.
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    } 

那3个方法只是remove的尺码不一致,其主逻辑都以均等的,即从队列中去除全数相配的要素。总体思索都以先从队首删除,假若去除了则队首

指向接下去的成分,重复那几个过程,直到第贰个不宽容的要素现身。接着从这么些成分之后(after
front卡塔尔最初查找并删除,

艺术是链表删除后叁个节点的法子,即p.next=nn。注意这里都以剔除全体相称的新闻,实际不是首先个门道特其余。

末段看下队列的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();
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }  

5、Thread:线程,负担调解整个音信循环,即新闻循环的进行地方。获取loop

quit方法依照所传参数safe的值,有2种分歧的脱离政策,要是是safe的退出,则实行removeAllFutureMessagesLocked(),

其内部的逻辑为若是队首的要素还未有到期那表明队列中任何具备的因素也都没到期,所以大器晚成律删除全体的新闻即调用

removeAllMessagesLocked();不然遍历队列找到第二个p.when>now那样的message成分p,(更新队列的尾巴p.next=null,

缩水队列卡塔尔从p开端从来到行列甘休都是要被删掉的因素,全体删减之;纵然是unsafe的淡出,则具有message都直接被去除并

回笼即调用removeAllMessagesLocked()。

     
Message是链表结构,MessageQueue中的大多操作都以依附链表,看起来不方便的话,能够描绘图,就很清晰啦。。。

Message的源码剖判:http://www.cnblogs.com/jycboy/p/5786551.html

 

MessageQueue源码深入分析:http://www.cnblogs.com/jycboy/p/5786682.html

 

Handler源码解析:http://www.cnblogs.com/jycboy/p/5791457.html

 

Message源码深入解析:http://www.cnblogs.com/jycboy/p/5786551.html

 

中间转播申明出处: http://www.cnblogs.com/jycboy/p/5786682.html

Looper.loop();

Public staticvoidloop(){

finalLooperme=myLooper();

}

//再次来到和线程相关的looper

Public staticLoopermyLooper(){

returnsThreadLocal.get();

}

Android系统的音信队列和消息循环都是照准实际线程的,多个线程可以存在(当然也足以空头支票卡塔尔二个新闻队列和三个音信循环(Looper卡塔尔,特定线程的音讯只好分发给本线程,不可能举行跨线程,跨进度通信。不过成立的行事线程默许是从未消息循环和消息队列的,如若想让该

线程具备音讯队列和音信循环,须要在线程中首先调用Looper.prepare()来创制音讯队列,然后调用Looper.loop()步向消息循环。
如下例所示:

class LooperThread

extends Thread {

public Handler mHandler;

public void run() {

Looper.prepare();

mHandler = new Handler() {

public void handleMessage(Messagemsg) {

// process incoming messageshere

}

};

Looper.loop();

}

}

那样你的线程就全数了新闻管理体制了,在Handler中举办音讯管理。

Activity是一个UI线程,运维于主线程中,Android系统在运营的时候会为Activity创制贰个信息队列和消息循环(Looper卡塔 尔(英语:State of Qatar)。详细完结请参考ActivityThread.java文件

Android应用程序进度在起步的时候,会在经过中加载ActivityThread类,何况履行这么些类的main函数,应用程序的新闻循环进度就是在此个main函数里面实现的

public final class

ActivityThread {

……

public

static final void main(String[] args) {

……

Looper.prepareMainLooper();

……

ActivityThread

thread = new ActivityThread();

thread.attach(false);

……

Looper.loop();

……

thread.detach();

……

}

}

其生机勃勃函数做了两件业务,一是在主线程中开创了八个ActivityThread实例,二是经过Looper类使主线程进入音讯循环中

初叶化音信队列

class LooperThread

extends Thread {

public Handler mHandler;

public void run() {

Looper.prepare();

mHandler = new Handler() {

public void handleMessage(Messagemsg) {

// process incoming messageshere

}

};

Looper.loop();

}

}

首假如革命标识的两句,首先调用prepare起头化MessageQueue与Looper,然后调用loop步入音信循环。先看一下Looper.prepare。

public static void

prepare() {

prepare(true);

}

private static void

prepare(boolean quitAllowed) {

if (sThreadLocal.get() != null) {

throw new RuntimeException(“Onlyone Looper may be created per thread”);

}

sThreadLocal.set(new Looper(quitAllowed));

}

重载函数,quitAllowed默以为true,从名字能够看出来正是新闻循环是或不是足以脱离,暗许是可脱离的,Main线程(UI线程卡塔 尔(英语:State of Qatar)先导化音信循环时会调用prepareMainLooper,传进去的是false。使用了ThreadLocal,各种线程能够初阶化三个Looper。

private Looper(boolean quitAllowed) {

mQueue = new MessageQueue(quitAllowed);

mThread = Thread.currentThread();

}

MessageQueue(boolean quitAllowed) {

mQuitAllowed = quitAllowed;

mPtr = nativeInit();//mPtr记录native新闻队列的新闻

}

在Looper初阶化时,新建了多个MessageQueue的靶子保存了在成员mQueue中。MessageQueue的构造函数是包可知性,所以大家是回天无力直接运用的,在MessageQueue开头化的时候调用了nativeInit,那是叁个Native方法:

android_lovebet下载,os_MessageQueue_nativeInit();

static jlong

android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {

NativeMessageQueue*nativeMessageQueue = new
NativeMessageQueue();//早先化native音信队列

if (!nativeMessageQueue) {

jniThrowRuntimeException(env,”Unable to allocate native queue”);

return 0;

}

nativeMessageQueue->incStrong(env);

returnreinterpret_cast(nativeMessageQueue);

}

在nativeInit中,new了二个Native层的MessageQueue的目的,并将其地方保存在了Java层MessageQueue的积极分子mPtr中,Android中有多数这么的兑现,一个类在Java层与Native层都有贯彻,通过JNI的GetFieldID与SetInt菲尔德把Native层的类的实例地址保存到Java层类的实例的mPtr成员中,举例Parcel。

再看NativeMessageQueue的实现:

new

NativeMessageQueue();

NativeMessageQueue::NativeMessageQueue()

: mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {

mLooper =Looper::getForThread(); //获取TLS中的Looper对象

if (mLooper == NULL) {

mLooper = newLooper(false); //创建native层的Looper

Looper::setForThread(mLooper); //保存native层的Looper到TLS中

}

}

Looper::getForThread(),功效类比于Java层的Looper.myLooper();

Looper::setForThread(mLooper),功用类比于Java层的ThreadLocal.set();

NativeMessageQueue::NativeMessageQueue()

: mInCallback(false), mExceptionObj(NULL) {

mLooper = Looper::getForThread();

if (mLooper == NULL) {

mLooper = new Looper(false);

Looper::setForThread(mLooper);

}

}

在NativeMessageQueue的构造函数中获取了三个Native层的Looper对象,Native层的Looper也运用了线程本地存款和储蓄

发送消息

因而Looper.prepare起先化好新闻队列后就足以调用Looper.loop踏向新闻循环了,然后大家就足以向音讯队列发送信息,音信循环就能够收取新闻实行拍卖,在看消息管理早前,先看一下消息是怎么被加多到音信队列的。

在Java层,Message类表示三个消息对象,要发送新闻首先将要先获得一个消息对象,Message类的构造函数是public的,可是不提出间接new
Message,Message内部保存了三个缓存的音讯池,大家得以用obtain从缓存池获得二个消息,Message使用完后系统会调用recycle回笼,若是和煦new比较多Message,每一遍使用完后系统放入缓存池,会据有相当多内部存款和储蓄器的,如下所示:

public static

Message obtain() {

synchronized (sPoolSync) {

if (sPool != null) {

Message m = sPool;

sPool = m.next;

m.next = null;

sPoolSize–;

return m;

}

}

return new Message();

}

public void recycle() {

clearForRecycle();

synchronized (sPoolSync) {

if (sPoolSize < MAX_POOL_SIZE) {

next = sPool;

sPool = this;

sPoolSize++;

}

}

}

Message内部通过next成员落到实处了一个链表,那样sPool就了为了一个Messages的缓存链表。

音信对象获得到了怎么发送呢,我们都知道是透过Handler的post、sendMessage等方法,其实这个措施最后都以调用的同二个办法sendMessageAtTime:

public boolean

sendMessageAtTime(Message msg, long uptimeMillis) {

MessageQueue queue = mQueue;

if (queue == null) {

RuntimeException e = newRuntimeException(

this + “sendMessageAtTime() called with no mQueue”);

Log.w(“Looper”,e.getMessage(), e);

return false;

}

return enqueueMessage(queue, msg,uptimeMillis);

}

sendMessageAtTime获取到音信队列然后调用enqueueMessage方法,音讯队列mQueue是从与Handler关联的Looper获得的。

private boolean

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

msg.target = this;

if (mAsynchronous) {

msg.setAsynchronous(true);

}

return queue.enqueueMessage(msg,uptimeMillis);

}

enqueueMessage

接下去看一下是怎么MessageQueue的enqueueMessage。

final boolean

enqueueMessage(Message msg, long when) {

if (msg.isInUse()) {

throw newAndroidRuntimeException(msg + ” This message is already in
use.”);

}

if (msg.target == null) {

throw newAndroidRuntimeException(“Message must have a target.”);

}

boolean needWake;

synchronized (this) {

if (mQuiting) {

RuntimeException e = newRuntimeException(

msg.target + “sending message to a Handler on a dead thread”);

Log.w(“MessageQueue”,e.getMessage(), e);

return false;

}

msg.when = when;

Message p = mMessages;

if (p == null || when == 0 || when< p.when) {

// New head, wake up the eventqueue if blocked.

msg.next = p;

mMessages = msg;

needWake = mBlocked;

} else {

// Inserted within the middleof the queue.Usually we don’t have towake

// up the event queue unlessthere is a barrier at the head of the queue

// and the message is theearliest asynchronous message in the queue.

needWake = mBlocked &&p.target == null && msg.isAsynchronous();

Message prev;

for (;;) {

prev = p;

p = p.next;

if (p == null || when

break;

}

if (needWake &&p.isAsynchronous()) {

needWake = false;

}

}

msg.next = p; // invariant: p== prev.next

prev.next = msg;

}

}

if (needWake) {

nativeWake(mPtr);

}

return true;

}

在enqueueMessage中首先判别,假设当前的音信队列为空,大概新添长的音讯的实施时间when是0,恐怕新扩充长的消息的实行时间比新闻队列头的新闻的推行时间还早,就把新闻增添到信息队列头(音讯队列准期间排序卡塔尔国,否则将在找到确切的职分将日前信息增加到音信队列。

音信循环

音信队列起头化好了,也清楚怎么发消息了,下边正是怎么管理音讯了,看Handler.loop函数:

public static void

loop() {

final Looper me =myLooper();//从该线程中抽出对应的looper对象

if (me == null) {

throw new RuntimeException(“NoLooper; Looper.prepare() wasn’t called on
this thread.”);

}

final MessageQueue queue = me.mQueue;//取音信队列对象…

// Make sure the identity of thisthread is that of the local process,

// and keep track of what that identitytoken actually is.

Binder.clearCallingIdentity();

final long ident =Binder.clearCallingIdentity();

for (;;) {

Message msg = queue.next();// might block取新闻队列中的三个待管理新闻..

if (msg == null) {

// No message indicates thatthe message queue is quitting.

return;

}

// This must be in a localvariable, in case a UI event sets the logger

Printer logging = me.mLogging;

if (logging != null) {

logging.println(“>>>>> Dispatching to ” +msg.target + ” ”
+

msg.callback + “:” + msg.what);

}

msg.target.dispatchMessage(msg);

if (logging != null) {

logging.println(“<<<<< Finished to ” +msg.target + ” ” +
msg.callback);

}

// Make sure that during the courseof dispatching the

// identity of the thread wasn’tcorrupted.

final long newIdent =Binder.clearCallingIdentity();

if (ident != newIdent) {

Log.wtf(TAG, “Threadidentity changed from 0x”

+Long.toHexString(ident) + ” to 0x”

+Long.toHexString(newIdent) + ” while dispatching to “

+msg.target.getClass().getName() + ” “

+ msg.callback + “what=” + msg.what);

}

msg.recycle();

}

}

loop每便从MessageQueue抽出三个Message,调用msg.target.dispatchMessage(msg),target正是发送message时跟message关联的handler,那样就调用到了熟习的dispatchMessage,Message被拍卖后会被recycle。当queue.next重临null时会退出新闻循环,接下去就看一下MessageQueue.next是怎么收取音讯的,又会在何时回来null。

final Message next()

{

int pendingIdleHandlerCount = -1; // -1only during first iteration

int nextPollTimeoutMillis = 0;

for (;;) {

if (nextPollTimeoutMillis != 0) {

Binder.flushPendingCommands();

}

nativePollOnce(mPtr,nextPollTimeoutMillis);

synchronized (this) {

if (mQuiting) {

return null;

}

// Try to retrieve the nextmessage.Return if found.

final long now =SystemClock.uptimeMillis();

Message prevMsg = null;

Message msg = mMessages;

if (msg != null &&msg.target == null) {

// Stalled by abarrier.Find the next asynchronousmessage in the queue.

do {

prevMsg = msg;

msg = msg.next;

} while (msg != null&& !msg.isAsynchronous());

}

if (msg != null) {

if (now < msg.when) {

// Next message is notready.Set a timeout to wake up when itis ready.

nextPollTimeoutMillis =(int) Math.min(msg.when – now,
Integer.MAX_VALUE);

} else {

// Got a message.

mBlocked = false;

if (prevMsg != null) {

prevMsg.next =msg.next;

} else {

mMessages =msg.next;

}

msg.next = null;

if (false)Log.v(“MessageQueue”, “Returning message: ” + msg);

msg.markInUse();

return msg;

}

} else {

// No more messages.

nextPollTimeoutMillis = -1;

}

// If first time idle, then getthe number of idlers to run.

// Idle handles only run if thequeue is empty or if the first message

// in the queue (possibly abarrier) is due to be handled in the future.

if (pendingIdleHandlerCount< 0

&& (mMessages== null || now < mMessages.when)) {

pendingIdleHandlerCount =mIdleHandlers.size();

}

if (pendingIdleHandlerCount<= 0) {

// No idle handlers torun.Loop and wait some more.

mBlocked = true;

continue;

}

if (mPendingIdleHandlers ==null) {

mPendingIdleHandlers = newIdleHandler[Math.max(pendingIdleHandlerCount,
4)];

}

mPendingIdleHandlers =mIdleHandlers.toArray(mPendingIdleHandlers);

}

// Run the idle handlers.

// We only ever reach this codeblock during the first iteration.

for (int i = 0; i

final IdleHandler idler =mPendingIdleHandlers[i];

mPendingIdleHandlers[i] = null;// release the reference to the handler

boolean keep = false;

try {

keep = idler.queueIdle();

} catch (Throwable t) {

Log.wtf(“MessageQueue”, “IdleHandler threwexception”, t);

}

if (!keep) {

synchronized (this) {

mIdleHandlers.remove(idler);

}

}

}

// Reset the idle handler count to0 so we do not run them again.

pendingIdleHandlerCount = 0;

// While calling an idle handler, anew message could have been delivered

// so go back and look again for apending message without waiting.

nextPollTimeoutMillis = 0;

}

}

MessageQueue.next首先会调用nativePollOnce,然后后生可畏旦mQuiting为true就赶回null,Looper就能够退出新闻循环。

相关文章