您的位置:首页 > 其它

View.postDelayed()/post() 原理(2)

2017-08-09 10:58 141 查看

1.2 post到自身的一个runnable队列中

回头接着看View.post()

/**
* <p>Causes the Runnable to be added to the message queue.
* The runnable will be run on the user interface thread.</p>
*
* @param action The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
*         message queue.  Returns false on failure, usually because the
*         looper processing the message queue is exiting.
*
* @see #postDelayed
* @see #removeCallbacks
*/
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}

// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}


当mAttachInfo为null,即View没有attach到Window时,会把Runnable缓存到Run Queue,并且直接返回true。来看看getRunQueue():

/**
* Returns the queue of runnable for this view.
*
* @return the queue of runnables for this view
*/
private HandlerActionQueue getRunQueue() {
if (mRunQueue == null) {
mRunQueue = new HandlerActionQueue();
}
return mRunQueue;
}


这也是一个懒加载,并且可以看到没有做线程安全,显然是内部保证只在UI线程调用。从HanderActionQueue的类定义可以看到其功用:

/**
* Class used to enqueue pending work from Views when no Handler is attached.
*
* @hide Exposed for test framework only.
*/
public class HandlerActionQueue


在View.dispatchAttachedToWindow()中,有消费缓存到Run Queue的Runnable的逻辑:

mAttachInfo = info;
......
// Transfer all pending runnables.
if (mRunQueue != null) {
mRunQueue.executeActions(info.mHandler);
mRunQueue = null;
}


并且可以看到一旦dispatch并在mAttachInfo.mHandler中执行了缓存的Runnable,立刻解除mRunQueue的强引用,废弃掉HanderActionQueue对象。

在mAttachInfo.mHandler中执行,也意味着和1.1那一路逻辑是等效的。

多说一些,在HanderActionQueue(源代码与View同包)内部,使用了一个可增长数组来做缓存队列。HanderActionQueue.post():

public void post(Runnable action) {
postDelayed(action, 0);
}

public void postDelayed(Runnable action, long delayMillis) {
final HandlerAction handlerAction = new HandlerAction(action, delayMillis);

synchronized (this) {
if (mActions == null) {
mActions = new HandlerAction[4];
}
mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
mCount++;
}
}


先创建(线程安全)一个size为4的数组,然后使用GrowingArrayUtils.append()做可增长数组放入item。

GrowingArrayUtils这个类位于frameworks/base/core/java/com/android/internal/util/GrowingArrayUtils.java,是Android框架层的一个内部工具类。看看它相关的代码:

/**
* Appends an element to the end of the array, growing the array if there is no more room.
* @param array The array to which to append the element. This must NOT be null.
* @param currentSize The number of elements in the array. Must be less than or equal to
*                    array.length.
* @param element The element to append.
* @return the array to which the element was appended. This may be different than the given
*         array.
*/
public static <T> T[] append(T[] array, int currentSize, T element) {
assert currentSize <= array.length;

if (currentSize + 1 > array.length) {
@SuppressWarnings("unchecked")
T[] newArray = ArrayUtils.newUnpaddedArray(
(Class<T>) array.getClass().getComponentType(), growSize(currentSize));
System.arraycopy(array, 0, newArray, 0, currentSize);
array = newArray;
}
array[currentSize] = element;
return array;
}


/**
* Given the current size of an array, returns an ideal size to which the array should grow.
* This is typically double the given size, but should not be relied upon to do so in the
* future.
*/
public static int growSize(int currentSize) {
return currentSize <= 4 ? 8 : currentSize * 2;
}


可以看到是做过一些优化。可以作为类似需求的List之外的一种选择。如有时间,后续研究对比一下。(完)

View.postDelayed()/post() 原理(1)

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