您的位置:首页 > 产品设计 > UI/UE

MessageQueue.IdleHandler接口使用方法以及原理分析

2015-09-18 10:21 507 查看
转载出自:http://bbs.51cto.com/thread-1094228-1.html

MessageQueue.IdleHandler可以用来在线程空闲的时候,指定一个操作;有点类似Handler.postDelayed(Runnable r, long delayMillis),都是在将来的某一个时间

执行一个操作。

不过,使用IdleHandler的好处在于可以不用指定一个将来时间,只要线程空闲了,就可以执行它指定的操作。

比较适合那种需要在将来执行操作,但是又不知道需要指定多少延迟时间的操作。

一 使用方法

public class MainActivity extends Activity {

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

....

Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {

/**

* 返回值boolean 意思是needKeep

* true,表示要保留保留, 代表不移除这个idleHandler,可以反复执行

* false代表执行完毕之后就移除这个idleHandler, 也就是只执行一次

*/

@Override

public boolean queueIdle() {

Log.d("Sandy", "queueIdle");

Toast.makeText(MainActivity.this, "主线程空闲了", Toast.LENGTH_SHORT).show();

return false;

}

});

}

...

}

使用非常简单,只要使用Looper.myQueue().addIdleHandler(xxx)就可以了。这样,在线程空闲,也就是activity创建完毕之后,它会执行queueIdle里面的代码。

返回值的含义在代码里面注释说明了,

true,表示needKeep,也就是保留,当queueIdle执行完毕之后,不会移除这个IdleHandler

false,表示这个IdleHandler不需要保留,也就是只需要执行一遍。

二 原理说明

上面的效果看起来不错,那么在android里面怎么实现的呢?

下面,进行源代码分析..

1. Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {...}

先来看看MyQueue.addIdleHandler里面怎么实现的

代码路径:frameworks/base/core/java/android/os/MessageQueue.java

private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();

....

public void addIdleHandler(IdleHandler handler) {

if (handler == null) {

throw new NullPointerException("Can't add a null IdleHandler");

}

synchronized (this) {

mIdleHandlers.add(handler);

}

}

很简单,只是把IdleHandler对象放到mIdleHandlers这个集合里面罢了。 那么,android怎么使用这个集合的呢?

2. 线程的死循环

我们都知道,android里面消息机制的关键在于Looper.loop()方法,因为它把一个简单的线程做成了一个死循环,这样才能保证持续的响应消息。(不知道的可以先学习在Looper)

代码路径:frameworks/base/core/java/android/os/Looper.java

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;

// Make sure the identity of this thread is that of the local process,

// and keep track of what that identity token actually is.

Binder.clearCallingIdentity();

final long ident = Binder.clearCallingIdentity();

for (;;) {

Message msg = queue.next(); // might block

if (msg == null) {

// No message indicates that the message queue is quitting.

return;

}

// This must be in a local variable, 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);

...

msg.recycle();

}

}

从上面的loop()方法可以看出,它是一个死循环

for(;;){...}

这段代码的关键是 Message msg = queue.next(); // might block

这是去获取下一个消息,从注释可以看出,它是一个可能阻塞的方法,底层是使用epoll机制来实现的,这个暂且不提。

我们继续跟踪queue.next();

3. 代码路径

frameworks/base/core/java/android/os/MessageQueue.java

Message next() {

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

int nextPollTimeoutMillis = 0;

for (;;) {

if (nextPollTimeoutMillis != 0) {

Binder.flushPendingCommands();

}

// We can assume mPtr != 0 because the loop is obviously still running.

// The looper will not call this method after the loop quits.

nativePollOnce(mPtr, 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 (false) Log.v("MessageQueue", "Returning message: " + msg);

msg.markInUse();

return msg;

}

} else {

// No more messages.

nextPollTimeoutMillis = -1;

}

...

// 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("MessageQueue", "IdleHandler threw exception", t);

}

if (!keep) {

synchronized (this) {

mIdleHandlers.remove(idler);

}

}

}

...

}

}

这段代码首先去底层获取一个消息,nativePollOnce(mPtr, nextPollTimeoutMillis); 这个先不分析。

当获取到消息之后,正常逻辑是得到一个正常的消息,然后返回给Looper去执行这个消息。

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 (false) Log.v("MessageQueue", "Returning message: " + msg);

msg.markInUse();

return msg;

}

}

但是,如果返回的消息等于null的话,那么就暂时不会返回,而是继续往下面执行

else {

// No more messages.

nextPollTimeoutMillis = -1;

}

然后,它首先判断pendingIdleHandlerCount的个数,这个IdleHandler就是我们最开始的时候添加的IdleHandler。

如果有IdleHandler的话,就执行

// 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("MessageQueue", "IdleHandler threw exception", t);

}

if (!keep) {

synchronized (this) {

mIdleHandlers.remove(idler);

}

}

}

逐个调用IdleHandler的queueIdle方法,

keep = idler.queueIdle();

然后根据返回值决定要不要keep这个IdleHander,如果返回false,也就是不保留的话,就执行移除IdleHandler的操作,这样下次线程再空闲的时候,就不会调用这个IdleHandler了。

if (!keep) {

synchronized (this) {

mIdleHandlers.remove(idler);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: