@linux1s1s
2017-01-22T08:23:25.000000Z
字数 3666
阅读 3700
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 成员方法
@Overridepublic 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 {@Overridepublic 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 分析(下) 继续分析,精彩还有,别走开。
