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了,

那就找点其余事干)。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个接下去要用到的变量,紧接着走入Infinitifor循环中,其某次循环主要做那样几件业务:

  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队列中抽出来(类似单链表的去除操作),并实践

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只会在率先次巡回的时候实践三遍),将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)。详细完毕请参考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线程)初阶化音讯循环时会调用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_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与SetIntField把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就能够退出音讯循环。

相关文章