[关闭]
@linux1s1s 2017-01-22T16:23:25.000000Z 字数 3666 阅读 3314

Android View 分析(中)

AndroidView 2015-05


ViewRootImpl.setView(...)

我们接着Android View 分析(上)继续分析,首先分析 setView(...) 这个方法。

  1. /**
  2. * We have one child
  3. */
  4. public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
  5. synchronized (this) {
  6. if (mView == null) {
  7. mView = view;
  8. ...
  9. mAdded = true;
  10. int res; /* = WindowManagerImpl.ADD_OKAY; */
  11. // Schedule the first layout -before- adding to the window
  12. // manager, to make sure we do the relayout before receiving
  13. // any other events from the system.
  14. requestLayout();
  15. ...
  16. if ((mWindowAttributes.inputFeatures
  17. & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
  18. mInputChannel = new InputChannel();
  19. }
  20. try {
  21. mOrigWindowType = mWindowAttributes.type;
  22. mAttachInfo.mRecomputeGlobalAttributes = true;
  23. collectViewAttributes();
  24. res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
  25. getHostVisibility(), mDisplay.getDisplayId(),
  26. mAttachInfo.mContentInsets, mInputChannel);
  27. } catch (RemoteException e) {
  28. mAdded = false;
  29. mView = null;
  30. mAttachInfo.mRootView = null;
  31. mInputChannel = null;
  32. mFallbackEventHandler.setView(null);
  33. unscheduleTraversals();
  34. setAccessibilityFocus(null, null);
  35. throw new RuntimeException("Adding window failed", e);
  36. } finally {
  37. if (restore) {
  38. attrs.restore();
  39. }
  40. }
  41. }
  42. }
  43. }

上述操作执行完成之后,ViewRoot类的成员函数setView就可以将成员变量mAdded的值设置为true了,表示当前正在处理的一个ViewRoot对象已经关联好一个View对象了。接下来,ViewRoot类的成员函数setView还需要执行两个操作:

ViewRootImpl.requestLayout(...)

这里我们打算继续追踪 ViewRootImpl 类的 requestLayout 成员方法

  1. @Override
  2. public void requestLayout() {
  3. if (!mHandlingLayoutInLayoutRequest) {
  4. checkThread();
  5. mLayoutRequested = true;
  6. scheduleTraversals();
  7. }
  8. }

在执行 scheduleTraversals() 方法之前,先做个安全检查,哪些条件不可以执行scheduleTraversals() 方法呢,从上面的代码片段可知,

上面两种情况,只要满足其一就不会执行scheduleTraversals() 方法。

如此层层保护scheduleTraversals成员方法,那么很有必要对该方法探个究竟

  1. void scheduleTraversals() {
  2. if (!mTraversalScheduled) {
  3. mTraversalScheduled = true;
  4. mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
  5. mChoreographer.postCallback(
  6. Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
  7. if (!mUnbufferedInputDispatch) {
  8. scheduleConsumeBatchedInput();
  9. }
  10. notifyRendererOfFramePending();
  11. }
  12. }

终于见到庐山真面目了,L5 有一个我们比较熟悉的方法:postCallback(...),我们追踪下去看看,是不是我们平常熟悉的post方法
进入 ChoreographerpostCallbackDelayedInternal 成员方法

  1. private void postCallbackDelayedInternal(int callbackType,
  2. Object action, Object token, long delayMillis) {
  3. if (DEBUG) {
  4. Log.d(TAG, "PostCallback: type=" + callbackType
  5. + ", action=" + action + ", token=" + token
  6. + ", delayMillis=" + delayMillis);
  7. }
  8. synchronized (mLock) {
  9. final long now = SystemClock.uptimeMillis();
  10. final long dueTime = now + delayMillis;
  11. mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
  12. if (dueTime <= now) {
  13. scheduleFrameLocked(now);
  14. } else {
  15. Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
  16. msg.arg1 = callbackType;
  17. msg.setAsynchronous(true);
  18. mHandler.sendMessageAtTime(msg, dueTime);
  19. }
  20. }
  21. }

最后一行显示这个和我们熟悉的post异曲同工,所以我们直接进入执行语句体 Run()方法体:
先找到这个Runnable类的实例

  1. final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

接着进入run()方法看看执行体:

  1. final class TraversalRunnable implements Runnable {
  2. @Override
  3. public void run() {
  4. doTraversal();
  5. }
  6. }

很简单,就一句代码,进一步看一下这个巨简洁的单行方法

  1. void doTraversal() {
  2. if (mTraversalScheduled) {
  3. mTraversalScheduled = false;
  4. mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
  5. if (mProfile) {
  6. Debug.startMethodTracing("ViewAncestor");
  7. }
  8. Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
  9. try {
  10. performTraversals();
  11. } finally {
  12. Trace.traceEnd(Trace.TRACE_TAG_VIEW);
  13. }
  14. if (mProfile) {
  15. Debug.stopMethodTracing();
  16. mProfile = false;
  17. }
  18. }
  19. }

上面代码片段,是不是在第12行看到熟悉的老朋友啦:performTraversals() 对的,就是这个performTraversals方法,关于这个方法,为啥说是老朋友,因为这个方法是所有介绍Android View的起点,接下来对于这个方法我们放在 Android View 分析(下) 继续分析,精彩还有,别走开。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注