@linux1s1s
2017-01-22T16:23:25.000000Z
字数 3666
阅读 3314
AndroidView
2015-05
我们接着Android View 分析(上)继续分析,首先分析 setView(...)
这个方法。
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
...
mAdded = true;
int res; /* = WindowManagerImpl.ADD_OKAY; */
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
...
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mInputChannel);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
mInputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
}
}
}
上述操作执行完成之后,ViewRoot类的成员函数setView就可以将成员变量mAdded的值设置为true了,表示当前正在处理的一个ViewRoot对象已经关联好一个View对象了。接下来,ViewRoot类的成员函数setView还需要执行两个操作:
ViewRootImpl
类的另外一个成员函数 requestLayout
来请求对应用程序窗口视图的UI作第一次布局。ViewRootImpl
类的静态成员变量sWindowSession所描述的一个类型为Session的Binder代理对象的成员函数add来请求WindowManagerService增加一个WindowState对象,以便可以用来描述当前正在处理的一个ViewRoot所关联的一个应用程序窗口。这里我们打算继续追踪 ViewRootImpl
类的 requestLayout
成员方法
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
在执行 scheduleTraversals()
方法之前,先做个安全检查,哪些条件不可以执行scheduleTraversals()
方法呢,从上面的代码片段可知,
LayoutInLayout
请求时上面两种情况,只要满足其一就不会执行scheduleTraversals()
方法。
如此层层保护scheduleTraversals成员方法,那么很有必要对该方法探个究竟
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
}
}
终于见到庐山真面目了,L5 有一个我们比较熟悉的方法:postCallback(...),我们追踪下去看看,是不是我们平常熟悉的post方法
进入 Choreographer
类 postCallbackDelayedInternal
成员方法
private void postCallbackDelayedInternal(int callbackType,
Object action, Object token, long delayMillis) {
if (DEBUG) {
Log.d(TAG, "PostCallback: type=" + callbackType
+ ", action=" + action + ", token=" + token
+ ", delayMillis=" + delayMillis);
}
synchronized (mLock) {
final long now = SystemClock.uptimeMillis();
final long dueTime = now + delayMillis;
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
scheduleFrameLocked(now);
} else {
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
最后一行显示这个和我们熟悉的post异曲同工,所以我们直接进入执行语句体 Run()方法体:
先找到这个Runnable类的实例
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
接着进入run()方法看看执行体:
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
很简单,就一句代码,进一步看一下这个巨简洁的单行方法
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
try {
performTraversals();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
上面代码片段,是不是在第12行看到熟悉的老朋友啦:performTraversals()
对的,就是这个performTraversals方法,关于这个方法,为啥说是老朋友,因为这个方法是所有介绍Android View的起点,接下来对于这个方法我们放在 Android View 分析(下) 继续分析,精彩还有,别走开。