篇文章基于 Android N - 7.1.1 主要分析下 performTraversals 方法的执行流程;
1 回顾 我们来回顾下,当请求到 Vsync 信号后就会触发 callback:
1.1 TraversalRunnable.run TraversalRunnable 只是一个 runnable,其内部会调用另外一个方法:doTraversal()
1 2 3 4 5 6 7 8 final class TraversalRunnable implements Runnable { @Override public void run () { doTraversal(); } } final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
1.2 doTraversal 开始遍历了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void doTraversal () { if (mTraversalScheduled) { mTraversalScheduled = false ; mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); if (mProfile) { Debug.startMethodTracing("ViewAncestor" ); } performTraversals(); if (mProfile) { Debug.stopMethodTracing(); mProfile = false ; } } }
我们看到,最后调用了 performTraversals 方法!!
2 ViewRootImpl 执行视图遍历,这个方法很长很长:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 private void performTraversals () { final View host = mView; if (DBG) { System.out.println("======================================" ); System.out.println("performTraversals" ); host.debug(); } if (host == null || !mAdded) return ; mIsInTraversal = true ; mWillDrawSoon = true ; boolean windowSizeMayChange = false ; boolean newSurface = false ; boolean surfaceChanged = false ; WindowManager.LayoutParams lp = mWindowAttributes; int desiredWindowWidth; int desiredWindowHeight; final int viewVisibility = getHostVisibility(); final boolean viewVisibilityChanged = !mFirst && (mViewVisibility != viewVisibility || mNewSurfaceNeeded); final boolean viewUserVisibilityChanged = !mFirst && ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE)); WindowManager.LayoutParams params = null ; if (mWindowAttributesChanged) { mWindowAttributesChanged = false ; surfaceChanged = true ; params = lp; } CompatibilityInfo compatibilityInfo = mDisplay.getDisplayAdjustments().getCompatibilityInfo(); if (compatibilityInfo.supportsScreen() == mLastInCompatMode) { params = lp; mFullRedrawNeeded = true ; mLayoutRequested = true ; if (mLastInCompatMode) { params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; mLastInCompatMode = false ; } else { params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; mLastInCompatMode = true ; } } mWindowAttributesChangesFlag = 0 ; Rect frame = mWinFrame; if (mFirst) { mFullRedrawNeeded = true ; mLayoutRequested = true ; if (shouldUseDisplaySize(lp)) { Point size = new Point(); mDisplay.getRealSize(size); desiredWindowWidth = size.x; desiredWindowHeight = size.y; } else { Configuration config = mContext.getResources().getConfiguration(); desiredWindowWidth = dipToPx(config.screenWidthDp); desiredWindowHeight = dipToPx(config.screenHeightDp); } mAttachInfo.mUse32BitDrawingCache = true ; mAttachInfo.mHasWindowFocus = false ; mAttachInfo.mWindowVisibility = viewVisibility; mAttachInfo.mRecomputeGlobalAttributes = false ; mLastConfiguration.setTo(host.getResources().getConfiguration()); mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) { host.setLayoutDirection(mLastConfiguration.getLayoutDirection()); } host.dispatchAttachedToWindow(mAttachInfo, 0 ); mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true ); dispatchApplyInsets(host); } else { desiredWindowWidth = frame.width(); desiredWindowHeight = frame.height(); if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) { if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame); mFullRedrawNeeded = true ; mLayoutRequested = true ; windowSizeMayChange = true ; } } if (viewVisibilityChanged) { mAttachInfo.mWindowVisibility = viewVisibility; host.dispatchWindowVisibilityChanged(viewVisibility); if (viewUserVisibilityChanged) { host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE); } if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) { endDragResizing(); destroyHardwareResources(); } if (viewVisibility == View.GONE) { mHasHadWindowFocus = false ; } } if (mAttachInfo.mWindowVisibility != View.VISIBLE) { host.clearAccessibilityFocus(); } getRunQueue().executeActions(mAttachInfo.mHandler); boolean insetsChanged = false ; boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw); if (layoutRequested) { final Resources res = mView.getContext().getResources(); if (mFirst) { mAttachInfo.mInTouchMode = !mAddedTouchMode; ensureTouchModeLocally(mAddedTouchMode); } else { if (!mPendingOverscanInsets.equals(mAttachInfo.mOverscanInsets)) { insetsChanged = true ; } if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) { insetsChanged = true ; } if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) { insetsChanged = true ; } if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) { mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets); if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: " + mAttachInfo.mVisibleInsets); } if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) { insetsChanged = true ; } if (mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar) { insetsChanged = true ; } if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { windowSizeMayChange = true ; if (shouldUseDisplaySize(lp)) { Point size = new Point(); mDisplay.getRealSize(size); desiredWindowWidth = size.x; desiredWindowHeight = size.y; } else { Configuration config = res.getConfiguration(); desiredWindowWidth = dipToPx(config.screenWidthDp); desiredWindowHeight = dipToPx(config.screenHeightDp); } } } windowSizeMayChange |= measureHierarchy(host, lp, res, desiredWindowWidth, desiredWindowHeight); } if (collectViewAttributes()) { params = lp; } if (mAttachInfo.mForceReportNewAttributes) { mAttachInfo.mForceReportNewAttributes = false ; params = lp; } if (mFirst || mAttachInfo.mViewVisibilityChanged) { mAttachInfo.mViewVisibilityChanged = false ; int resizeMode = mSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { final int N = mAttachInfo.mScrollContainers.size(); for (int i=0 ; i<N; i++) { if (mAttachInfo.mScrollContainers.get(i).isShown()) { resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; } } if (resizeMode == 0 ) { resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; } if ((lp.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) { lp.softInputMode = (lp.softInputMode & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) | resizeMode; params = lp; } } } if (params != null ) { if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0 ) { if (!PixelFormat.formatHasAlpha(params.format)) { params.format = PixelFormat.TRANSLUCENT; } } mAttachInfo.mOverscanRequested = (params.flags & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0 ; } if (mApplyInsetsRequested) { mApplyInsetsRequested = false ; mLastOverscanRequested = mAttachInfo.mOverscanRequested; dispatchApplyInsets(host); if (mLayoutRequested) { windowSizeMayChange |= measureHierarchy(host, lp, mView.getContext().getResources(), desiredWindowWidth, desiredWindowHeight); } } if (layoutRequested) { mLayoutRequested = false ; } boolean windowShouldResize = layoutRequested && windowSizeMayChange && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT && frame.width() < desiredWindowWidth && frame.width() != mWidth) || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT && frame.height() < desiredWindowHeight && frame.height() != mHeight)); windowShouldResize |= mDragResizing && mResizeMode == RESIZE_MODE_FREEFORM; windowShouldResize |= mActivityRelaunched; final boolean computesInternalInsets = mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners() || mAttachInfo.mHasNonEmptyGivenInternalInsets; boolean insetsPending = false ; int relayoutResult = 0 ; boolean updatedConfiguration = false ; final int surfaceGenerationId = mSurface.getGenerationId(); final boolean isViewVisible = viewVisibility == View.VISIBLE; if (mFirst || windowShouldResize || insetsChanged || viewVisibilityChanged || params != null || mForceNextWindowRelayout) { mForceNextWindowRelayout = false ; if (isViewVisible) { insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged); } if (mSurfaceHolder != null ) { mSurfaceHolder.mSurfaceLock.lock(); mDrawingAllowed = true ; } boolean hwInitialized = false ; boolean contentInsetsChanged = false ; boolean hadSurface = mSurface.isValid(); try { if (DEBUG_LAYOUT) { Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" + host.getMeasuredHeight() + ", params=" + params); } if (mAttachInfo.mHardwareRenderer != null ) { if (mAttachInfo.mHardwareRenderer.pauseSurface(mSurface)) { mDirty.set(0 , 0 , mWidth, mHeight); } mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED); } relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString() + " overscan=" + mPendingOverscanInsets.toShortString() + " content=" + mPendingContentInsets.toShortString() + " visible=" + mPendingVisibleInsets.toShortString() + " visible=" + mPendingStableInsets.toShortString() + " outsets=" + mPendingOutsets.toShortString() + " surface=" + mSurface); if (mPendingConfiguration.seq != 0 ) { if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: " + mPendingConfiguration); updateConfiguration(new Configuration(mPendingConfiguration), !mFirst); mPendingConfiguration.seq = 0 ; updatedConfiguration = true ; } final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals( mAttachInfo.mOverscanInsets); contentInsetsChanged = !mPendingContentInsets.equals( mAttachInfo.mContentInsets); final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals( mAttachInfo.mVisibleInsets); final boolean stableInsetsChanged = !mPendingStableInsets.equals( mAttachInfo.mStableInsets); final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets); final boolean surfaceSizeChanged = (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0 ; final boolean alwaysConsumeNavBarChanged = mPendingAlwaysConsumeNavBar != mAttachInfo.mAlwaysConsumeNavBar; if (contentInsetsChanged) { mAttachInfo.mContentInsets.set(mPendingContentInsets); if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: " + mAttachInfo.mContentInsets); } if (overscanInsetsChanged) { mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets); if (DEBUG_LAYOUT) Log.v(mTag, "Overscan insets changing to: " + mAttachInfo.mOverscanInsets); contentInsetsChanged = true ; } if (stableInsetsChanged) { mAttachInfo.mStableInsets.set(mPendingStableInsets); if (DEBUG_LAYOUT) Log.v(mTag, "Decor insets changing to: " + mAttachInfo.mStableInsets); contentInsetsChanged = true ; } if (alwaysConsumeNavBarChanged) { mAttachInfo.mAlwaysConsumeNavBar = mPendingAlwaysConsumeNavBar; contentInsetsChanged = true ; } if (contentInsetsChanged || mLastSystemUiVisibility != mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested || mLastOverscanRequested != mAttachInfo.mOverscanRequested || outsetsChanged) { mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; mLastOverscanRequested = mAttachInfo.mOverscanRequested; mAttachInfo.mOutsets.set(mPendingOutsets); mApplyInsetsRequested = false ; dispatchApplyInsets(host); } if (visibleInsetsChanged) { mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets); if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: " + mAttachInfo.mVisibleInsets); } if (!hadSurface) { if (mSurface.isValid()) { newSurface = true ; mFullRedrawNeeded = true ; mPreviousTransparentRegion.setEmpty(); if (mAttachInfo.mHardwareRenderer != null ) { try { hwInitialized = mAttachInfo.mHardwareRenderer.initialize( mSurface); if (hwInitialized && (host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0 ) { mSurface.allocateBuffers(); } } catch (OutOfResourcesException e) { handleOutOfResourcesException(e); return ; } } } } else if (!mSurface.isValid()) { if (mLastScrolledFocus != null ) { mLastScrolledFocus.clear(); } mScrollY = mCurScrollY = 0 ; if (mView instanceof RootViewSurfaceTaker) { ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY); } if (mScroller != null ) { mScroller.abortAnimation(); } if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { mAttachInfo.mHardwareRenderer.destroy(); } } else if ((surfaceGenerationId != mSurface.getGenerationId() || surfaceSizeChanged) && mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null ) { mFullRedrawNeeded = true ; try { mAttachInfo.mHardwareRenderer.updateSurface(mSurface); } catch (OutOfResourcesException e) { handleOutOfResourcesException(e); return ; } } final boolean freeformResizing = (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFORM) != 0 ; final boolean dockedResizing = (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_DOCKED) != 0 ; final boolean dragResizing = freeformResizing || dockedResizing; if (mDragResizing != dragResizing) { if (dragResizing) { mResizeMode = freeformResizing ? RESIZE_MODE_FREEFORM : RESIZE_MODE_DOCKED_DIVIDER; startDragResizing(mPendingBackDropFrame, mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets, mPendingStableInsets, mResizeMode); } else { endDragResizing(); } } if (!USE_MT_RENDERER) { if (dragResizing) { mCanvasOffsetX = mWinFrame.left; mCanvasOffsetY = mWinFrame.top; } else { mCanvasOffsetX = mCanvasOffsetY = 0 ; } } } catch (RemoteException e) { } if (DEBUG_ORIENTATION) Log.v( TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface); mAttachInfo.mWindowLeft = frame.left; mAttachInfo.mWindowTop = frame.top; if (mWidth != frame.width() || mHeight != frame.height()) { mWidth = frame.width(); mHeight = frame.height(); } if (mSurfaceHolder != null ) { if (mSurface.isValid()) { mSurfaceHolder.mSurface = mSurface; } mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight); mSurfaceHolder.mSurfaceLock.unlock(); if (mSurface.isValid()) { if (!hadSurface) { mSurfaceHolder.ungetCallbacks(); mIsCreating = true ; mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder); SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); if (callbacks != null ) { for (SurfaceHolder.Callback c : callbacks) { c.surfaceCreated(mSurfaceHolder); } } surfaceChanged = true ; } if (surfaceChanged || surfaceGenerationId != mSurface.getGenerationId()) { mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder, lp.format, mWidth, mHeight); SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); if (callbacks != null ) { for (SurfaceHolder.Callback c : callbacks) { c.surfaceChanged(mSurfaceHolder, lp.format, mWidth, mHeight); } } } mIsCreating = false ; } else if (hadSurface) { mSurfaceHolder.ungetCallbacks(); SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder); if (callbacks != null ) { for (SurfaceHolder.Callback c : callbacks) { c.surfaceDestroyed(mSurfaceHolder); } } mSurfaceHolder.mSurfaceLock.lock(); try { mSurfaceHolder.mSurface = new Surface(); } finally { mSurfaceHolder.mSurfaceLock.unlock(); } } } final ThreadedRenderer hardwareRenderer = mAttachInfo.mHardwareRenderer; if (hardwareRenderer != null && hardwareRenderer.isEnabled()) { if (hwInitialized || mWidth != hardwareRenderer.getWidth() || mHeight != hardwareRenderer.getHeight() || mNeedsHwRendererSetup) { hardwareRenderer.setup(mWidth, mHeight, mAttachInfo, mWindowAttributes.surfaceInsets); mNeedsHwRendererSetup = false ; } } if (!mStopped || mReportNextDraw) { boolean focusChangedDueToTouchMode = ensureTouchModeLocally( (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0 ); if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight() || contentInsetsChanged || updatedConfiguration) { int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height); if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth=" + mWidth + " measuredWidth=" + host.getMeasuredWidth() + " mHeight=" + mHeight + " measuredHeight=" + host.getMeasuredHeight() + " coveredInsetsChanged=" + contentInsetsChanged); performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); int width = host.getMeasuredWidth(); int height = host.getMeasuredHeight(); boolean measureAgain = false ; if (lp.horizontalWeight > 0.0f ) { width += (int ) ((mWidth - width) * lp.horizontalWeight); childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY); measureAgain = true ; } if (lp.verticalWeight > 0.0f ) { height += (int ) ((mHeight - height) * lp.verticalWeight); childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); measureAgain = true ; } if (measureAgain) { if (DEBUG_LAYOUT) Log.v(mTag, "And hey let's measure once more: width=" + width + " height=" + height); performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); } layoutRequested = true ; } } } else { maybeHandleWindowMove(frame); } final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw); boolean triggerGlobalLayoutListener = didLayout || mAttachInfo.mRecomputeGlobalAttributes; if (didLayout) { performLayout(lp, mWidth, mHeight); if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0 ) { host.getLocationInWindow(mTmpLocation); mTransparentRegion.set(mTmpLocation[0 ], mTmpLocation[1 ], mTmpLocation[0 ] + host.mRight - host.mLeft, mTmpLocation[1 ] + host.mBottom - host.mTop); host.gatherTransparentRegion(mTransparentRegion); if (mTranslator != null ) { mTranslator.translateRegionInWindowToScreen(mTransparentRegion); } if (!mTransparentRegion.equals(mPreviousTransparentRegion)) { mPreviousTransparentRegion.set(mTransparentRegion); mFullRedrawNeeded = true ; try { mWindowSession.setTransparentRegion(mWindow, mTransparentRegion); } catch (RemoteException e) { } } } if (DBG) { System.out.println("======================================" ); System.out.println("performTraversals -- after setFrame" ); host.debug(); } } if (triggerGlobalLayoutListener) { mAttachInfo.mRecomputeGlobalAttributes = false ; mAttachInfo.mTreeObserver.dispatchOnGlobalLayout(); } if (computesInternalInsets) { final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets; insets.reset(); mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets); mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty(); if (insetsPending || !mLastGivenInsets.equals(insets)) { mLastGivenInsets.set(insets); final Rect contentInsets; final Rect visibleInsets; final Region touchableRegion; if (mTranslator != null ) { contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets); visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets); touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion); } else { contentInsets = insets.contentInsets; visibleInsets = insets.visibleInsets; touchableRegion = insets.touchableRegion; } try { mWindowSession.setInsets(mWindow, insets.mTouchableInsets, contentInsets, visibleInsets, touchableRegion); } catch (RemoteException e) { } } } if (mFirst) { if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: mView.hasFocus()=" + mView.hasFocus()); if (mView != null ) { if (!mView.hasFocus()) { mView.requestFocus(View.FOCUS_FORWARD); if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: requested focused view=" + mView.findFocus()); } else { if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: existing focused view=" + mView.findFocus()); } } } final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible; final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible; final boolean regainedFocus = hasWindowFocus && mLostWindowFocus; if (regainedFocus) { mLostWindowFocus = false ; } else if (!hasWindowFocus && mHadWindowFocus) { mLostWindowFocus = true ; } if (changedVisibility || regainedFocus) { boolean isToast = (mWindowAttributes == null ) ? false : (mWindowAttributes.type == WindowManager.LayoutParams.TYPE_TOAST); if (!isToast) { host.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); } } mFirst = false ; mWillDrawSoon = false ; mNewSurfaceNeeded = false ; mActivityRelaunched = false ; mViewVisibility = viewVisibility; mHadWindowFocus = hasWindowFocus; if (hasWindowFocus && !isInLocalFocusMode()) { final boolean imTarget = WindowManager.LayoutParams .mayUseInputMethod(mWindowAttributes.flags); if (imTarget != mLastWasImTarget) { mLastWasImTarget = imTarget; InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null && imTarget) { imm.onPreWindowFocus(mView, hasWindowFocus); imm.onPostWindowFocus(mView, mView.findFocus(), mWindowAttributes.softInputMode, !mHasHadWindowFocus, mWindowAttributes.flags); } } } if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0 ) { mReportNextDraw = true ; } boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible; if (!cancelDraw && !newSurface) { if (mPendingTransitions != null && mPendingTransitions.size() > 0 ) { for (int i = 0 ; i < mPendingTransitions.size(); ++i) { mPendingTransitions.get(i).startChangingAnimations(); } mPendingTransitions.clear(); } performDraw(); } else { if (isViewVisible) { scheduleTraversals(); } else if (mPendingTransitions != null && mPendingTransitions.size() > 0 ) { for (int i = 0 ; i < mPendingTransitions.size(); ++i) { mPendingTransitions.get(i).endChangingAnimations(); } mPendingTransitions.clear(); } } mIsInTraversal = false ; }
2.1.1 getHostVisibility 获取显示配置,看 DecorView(根 view group)是否显示:
1 2 3 4 int getHostVisibility () { return (mAppVisible || mForceDecorViewVisibility) ? mView.getVisibility() : View.GONE; }
当然,对于 DecorView,默认是可见的,所以这个方法返回的是 true;
2.1.2 shouldUseDisplaySize 是否要设置成屏幕的大小;
1 2 3 4 5 private static boolean shouldUseDisplaySize (final WindowManager.LayoutParams lp) { return lp.type == TYPE_STATUS_BAR_PANEL || lp.type == TYPE_INPUT_METHOD || lp.type == TYPE_VOLUME_OVERLAY; }
这里会根据 window 的类型,判断是否设置成屏幕的大小;
2.1.3 dispatchApplyInsets 使用 windowInserts
1 2 3 void dispatchApplyInsets (View host) { host.dispatchApplyWindowInsets(getWindowInsets(true )); }
2.1.4 ensureTouchModeLocally 确保已设置此窗口的触摸模式:
参数 boolean inTouchMode:取值为 relayoutResult & WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0,是否要进入 touch 模式;
1 2 3 4 5 6 7 8 9 10 11 12 private boolean ensureTouchModeLocally (boolean inTouchMode) { if (DBG) Log.d("touchmode" , "ensureTouchModeLocally(" + inTouchMode + "), current " + "touch mode is " + mAttachInfo.mInTouchMode); if (mAttachInfo.mInTouchMode == inTouchMode) return false ; mAttachInfo.mInTouchMode = inTouchMode; mAttachInfo.mTreeObserver.dispatchOnTouchModeChanged(inTouchMode); return (inTouchMode) ? enterTouchMode() : leaveTouchMode(); }
2.1.5 maybeHandleWindowMove 这里会处理下 window 移动的情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private void maybeHandleWindowMove (Rect frame) { final boolean windowMoved = mAttachInfo.mWindowLeft != frame.left || mAttachInfo.mWindowTop != frame.top; if (windowMoved) { if (mTranslator != null ) { mTranslator.translateRectInScreenToAppWinFrame(frame); } mAttachInfo.mWindowLeft = frame.left; mAttachInfo.mWindowTop = frame.top; } if (windowMoved || mAttachInfo.mNeedsUpdateLightCenter) { if (mAttachInfo.mHardwareRenderer != null ) { mAttachInfo.mHardwareRenderer.setLightCenter(mAttachInfo); } mAttachInfo.mNeedsUpdateLightCenter = false ; } }
2.2 measureHierarchy - 预测量 这里是在正式测量绘制前,做一次预测量,测量结果会保存在 mMeasuredWidth 和 mMeasuredHeight 中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 private boolean measureHierarchy (final View host, final WindowManager.LayoutParams lp, final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) { int childWidthMeasureSpec; int childHeightMeasureSpec; boolean windowSizeMayChange = false ; if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag, "Measuring " + host + " in display " + desiredWindowWidth + "x" + desiredWindowHeight + "..." ); boolean goodMeasure = false ; if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) { final DisplayMetrics packageMetrics = res.getDisplayMetrics(); res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true ); int baseSize = 0 ; if (mTmpValue.type == TypedValue.TYPE_DIMENSION) { baseSize = (int )mTmpValue.getDimension(packageMetrics); } if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize + ", desiredWindowWidth=" + desiredWindowWidth); if (baseSize != 0 && desiredWindowWidth > baseSize) { childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width); childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured (" + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec) + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec)); if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0 ) { goodMeasure = true ; } else { baseSize = (baseSize+desiredWindowWidth)/2 ; if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize=" + baseSize); childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width); performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured (" + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")" ); if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0 ) { if (DEBUG_DIALOG) Log.v(mTag, "Good!" ); goodMeasure = true ; } } } } if (!goodMeasure) { childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width); childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) { windowSizeMayChange = true ; } } if (DBG) { System.out.println("======================================" ); System.out.println("performTraversals -- after measure" ); host.debug(); } return windowSizeMayChange; }
这里是提前做一次预测量。
2.2.1 getRootMeasureSpec 根据 view 的布局参数计算出其布局度量规范 measure spec:
int windowSize :窗口的可用宽度或高度(mHeight/ mWidth)
int rootDimension :布局参数参数指定的宽度或高度(match_parent/ wrap_content/ lp.height(width))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 private static int getRootMeasureSpec (int windowSize, int rootDimension) { int measureSpec; switch (rootDimension) { case ViewGroup.LayoutParams.MATCH_PARENT: measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY); break ; case ViewGroup.LayoutParams.WRAP_CONTENT: measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST); break ; default : measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY); break ; } return measureSpec; }
对于 DecorView 来说,显然是第一个分支:
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
2.3 relayoutWindow - 通过 wms 计算窗口大小 请求 Wms 计算 Activity 窗口的大小以及过扫描区域边衬大小和可见区域边衬大小,同时返回可用的 Surface:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 private int relayoutWindow (WindowManager.LayoutParams params, int viewVisibility, boolean insetsPending) throws RemoteException { float appScale = mAttachInfo.mApplicationScale; boolean restore = false ; if (params != null && mTranslator != null ) { restore = true ; params.backup(); mTranslator.translateWindowLayout(params); } if (params != null ) { if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params); } mPendingConfiguration.seq = 0 ; if (params != null && mOrigWindowType != params.type) { if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { Slog.w(mTag, "Window type can not be changed after " + "the window is added; ignoring change of " + mView); params.type = mOrigWindowType; } } int relayoutResult = mWindowSession.relayout( mWindow, mSeq, params, (int ) (mView.getMeasuredWidth() * appScale + 0.5f ), (int ) (mView.getMeasuredHeight() * appScale + 0.5f ), viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0 , mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets, mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration, mSurface); mPendingAlwaysConsumeNavBar = (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0 ; if (restore) { params.restore(); } if (mTranslator != null ) { mTranslator.translateRectInScreenToAppWinFrame(mWinFrame); mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets); mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets); mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets); mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets); } return relayoutResult; }
可以看到,这里的核心逻辑就是:
通过 WindowSession 来请求 wms 计算 view 的宽高;
同时会初始化 mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets, mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration, mSurface,对于 Surface,触发其 readFromParcel 方法;
我们去看看 IWindowSession.aidl 文件:
1 2 3 4 5 6 int relayout (IWindow window, int seq, in WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, int flags, out Rect outFrame, out Rect outOverscanInsets, out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets, out Rect outOutsets, out Rect outBackdropFrame, out Configuration outConfig, out Surface outSurface) ;
可以看到,我们初始化的那几个成员变量都是用 out 修饰的,这里我们简单回顾下 in 和 out 的区别:
in 修饰的参数传递到服务方,服务方对实参的任何改变,不会反应给调用方。
out 修饰的参数,不会真正传到服务方,只是传一个实参的初始值过去,但服务方对实参的任何改变,在调用结束后会反应给调用方。
这里实参只是作为返回值来使用的,这样除了 return 那里的返回值,还可以返回另外的东西;
inout 参数则是上面二者的结合,实参会顺利传到服务方,且服务方对实参的任何改变,在调用结束后会反应回调用方。
这里的参数:childWidthMeasureSpec 和 childHeightMeasureSpec 是 root view,也就是 DecorView 的测量标准!
1 2 3 4 5 6 7 8 9 private void performMeasure (int childWidthMeasureSpec, int childHeightMeasureSpec) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure" ); try { mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } }
对于 mView.measure 我们在下一篇文章中分析:
开始布局:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 private void performLayout (WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight) { mLayoutRequested = false ; mScrollMayChange = true ; mInLayout = true ; final View host = mView; if (host == null ) { return ; } if (DEBUG_ORIENTATION || DEBUG_LAYOUT) { Log.v(mTag, "Laying out " + host + " to (" + host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")" ); } Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout" ); try { host.layout(0 , 0 , host.getMeasuredWidth(), host.getMeasuredHeight()); mInLayout = false ; int numViewsRequestingLayout = mLayoutRequesters.size(); if (numViewsRequestingLayout > 0 ) { ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, false ); if (validLayoutRequesters != null ) { mHandlingLayoutInLayoutRequest = true ; int numValidRequests = validLayoutRequesters.size(); for (int i = 0 ; i < numValidRequests; ++i) { final View view = validLayoutRequesters.get(i); Log.w("View" , "requestLayout() improperly called by " + view + " during layout: running second layout pass" ); view.requestLayout(); } measureHierarchy(host, lp, mView.getContext().getResources(), desiredWindowWidth, desiredWindowHeight); mInLayout = true ; host.layout(0 , 0 , host.getMeasuredWidth(), host.getMeasuredHeight()); mHandlingLayoutInLayoutRequest = false ; validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters, true ); if (validLayoutRequesters != null ) { final ArrayList<View> finalRequesters = validLayoutRequesters; getRunQueue().post(new Runnable() { @Override public void run () { int numValidRequests = finalRequesters.size(); for (int i = 0 ; i < numValidRequests; ++i) { final View view = finalRequesters.get(i); Log.w("View" , "requestLayout() improperly called by " + view + " during second layout pass: posting in next frame" ); view.requestLayout(); } } }); } } } } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } mInLayout = false ; }
核心就是 ViewGroup 的 layout!!
我们这里会再看到有一个 list 列表:
1 ArrayList<View> mLayoutRequesters = new ArrayList<View>();
当一个 View.requestLayout() 方法被调用的时候,如果此时处于布局中,那么该 view 会被添加到 mLayoutRequesters 中:
requestLayoutDuringLayout
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 boolean requestLayoutDuringLayout (final View view) { if (view.mParent == null || view.mAttachInfo == null ) { return true ; } if (!mLayoutRequesters.contains(view)) { mLayoutRequesters.add(view); } if (!mHandlingLayoutInLayoutRequest) { return true ; } else { return false ; } }
(下面来自方法的翻译,感觉已经很清晰了)
一般不应该在布局过程中调用 requestLayout 方法,也就是说:正常情况下,应该是对该容器层次结构中的所有子级进行统一的一次性测量并在布局结束后进行统一布局。
如果仍然调用 requestLayout(),我们将通过在帧进行过程中将这些请求缓存下来,在布局结束后,我们会检查下,看是否还有待处理的布局请求,表示它们未被其容器层次结构正确处理。
如果真是这样,我们将清除树中的所有此类标志,并在该帧中强制第二次请求/度量/布局传递。 如果在第二次布局传递过程中收到了更多的 requestLayout 调用,我们会将这些请求发布到下一帧,以避免可能的无限循环。
此方法的返回值指示请求是否应该继续二次布局(如果是在第一次布局过程中收到的请求) 还是应该跳过并发布到下一个帧(如果是在第二个过程中收到的请求)
2.5.1 getValidLayoutRequesters 获取有效的布局请求!
如果在布局期间调用了 requestLayout 方法,则在布局期间会出发此方法。
它遍历了请求布局的视图列表,以根据层次结构中的可见性以及是否已经处理了它们来确定仍需要布局的视图(通常是 ListView 子级的情况)。
参数 layoutRequesters 保存的是 requestLayoutDuringLayout 的 View;
参数 secondLayoutRequests 表示的是是否是第二次布局,第一次布局时传入的 false;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 private ArrayList<View> getValidLayoutRequesters (ArrayList<View> layoutRequesters, boolean secondLayoutRequests) { int numViewsRequestingLayout = layoutRequesters.size(); ArrayList<View> validLayoutRequesters = null ; for (int i = 0 ; i < numViewsRequestingLayout; ++i) { View view = layoutRequesters.get(i); if (view != null && view.mAttachInfo != null && view.mParent != null && (secondLayoutRequests || (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) == View.PFLAG_FORCE_LAYOUT)) { boolean gone = false ; View parent = view; while (parent != null ) { if ((parent.mViewFlags & View.VISIBILITY_MASK) == View.GONE) { gone = true ; break ; } if (parent.mParent instanceof View) { parent = (View) parent.mParent; } else { parent = null ; } } if (!gone) { if (validLayoutRequesters == null ) { validLayoutRequesters = new ArrayList<View>(); } validLayoutRequesters.add(view); } } } if (!secondLayoutRequests) { for (int i = 0 ; i < numViewsRequestingLayout; ++i) { View view = layoutRequesters.get(i); while (view != null && (view.mPrivateFlags & View.PFLAG_FORCE_LAYOUT) != 0 ) { view.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT; if (view.mParent instanceof View) { view = (View) view.mParent; } else { view = null ; } } } } layoutRequesters.clear(); return validLayoutRequesters; }
不多说了!
开始绘制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 private void performDraw () { if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) { return ; } final boolean fullRedrawNeeded = mFullRedrawNeeded; mFullRedrawNeeded = false ; mIsDrawing = true ; Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw" ); try { draw(fullRedrawNeeded); } finally { mIsDrawing = false ; Trace.traceEnd(Trace.TRACE_TAG_VIEW); } if (mAttachInfo.mPendingAnimatingRenderNodes != null ) { final int count = mAttachInfo.mPendingAnimatingRenderNodes.size(); for (int i = 0 ; i < count; i++) { mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators(); } mAttachInfo.mPendingAnimatingRenderNodes.clear(); } if (mReportNextDraw) { mReportNextDraw = false ; if (mWindowDrawCountDown != null ) { try { mWindowDrawCountDown.await(); } catch (InterruptedException e) { Log.e(mTag, "Window redraw count down interruped!" ); } mWindowDrawCountDown = null ; } if (mAttachInfo.mHardwareRenderer != null ) { mAttachInfo.mHardwareRenderer.fence(); mAttachInfo.mHardwareRenderer.setStopped(mStopped); } if (LOCAL_LOGV) { Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle()); } if (mSurfaceHolder != null && mSurface.isValid()) { mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder); SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); if (callbacks != null ) { for (SurfaceHolder.Callback c : callbacks) { if (c instanceof SurfaceHolder.Callback2) { ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(mSurfaceHolder); } } } } try { mWindowSession.finishDrawing(mWindow); } catch (RemoteException e) { } } }
2.6.1 draw 执行绘制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 private void draw (boolean fullRedrawNeeded) { Surface surface = mSurface; if (!surface.isValid()) { return ; } if (DEBUG_FPS) { trackFPS(); } if (!sFirstDrawComplete) { synchronized (sFirstDrawHandlers) { sFirstDrawComplete = true ; final int count = sFirstDrawHandlers.size(); for (int i = 0 ; i< count; i++) { mHandler.post(sFirstDrawHandlers.get(i)); } } } scrollToRectOrFocus(null , false ); if (mAttachInfo.mViewScrollChanged) { mAttachInfo.mViewScrollChanged = false ; mAttachInfo.mTreeObserver.dispatchOnScrollChanged(); } boolean animating = mScroller != null && mScroller.computeScrollOffset(); final int curScrollY; if (animating) { curScrollY = mScroller.getCurrY(); } else { curScrollY = mScrollY; } if (mCurScrollY != curScrollY) { mCurScrollY = curScrollY; fullRedrawNeeded = true ; if (mView instanceof RootViewSurfaceTaker) { ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY); } } final float appScale = mAttachInfo.mApplicationScale; final boolean scalingRequired = mAttachInfo.mScalingRequired; int resizeAlpha = 0 ; final Rect dirty = mDirty; if (mSurfaceHolder != null ) { dirty.setEmpty(); if (animating && mScroller != null ) { mScroller.abortAnimation(); } return ; } if (fullRedrawNeeded) { mAttachInfo.mIgnoreDirtyState = true ; dirty.set(0 , 0 , (int ) (mWidth * appScale + 0.5f ), (int ) (mHeight * appScale + 0.5f )); } if (DEBUG_ORIENTATION || DEBUG_DRAW) { Log.v(mTag, "Draw " + mView + "/" + mWindowAttributes.getTitle() + ": dirty={" + dirty.left + "," + dirty.top + "," + dirty.right + "," + dirty.bottom + "} surface=" + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" + appScale + ", width=" + mWidth + ", height=" + mHeight); } mAttachInfo.mTreeObserver.dispatchOnDraw(); int xOffset = -mCanvasOffsetX; int yOffset = -mCanvasOffsetY + curScrollY; final WindowManager.LayoutParams params = mWindowAttributes; final Rect surfaceInsets = params != null ? params.surfaceInsets : null ; if (surfaceInsets != null ) { xOffset -= surfaceInsets.left; yOffset -= surfaceInsets.top; dirty.offset(surfaceInsets.left, surfaceInsets.right); } boolean accessibilityFocusDirty = false ; final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable; if (drawable != null ) { final Rect bounds = mAttachInfo.mTmpInvalRect; final boolean hasFocus = getAccessibilityFocusedRect(bounds); if (!hasFocus) { bounds.setEmpty(); } if (!bounds.equals(drawable.getBounds())) { accessibilityFocusDirty = true ; } } mAttachInfo.mDrawingTime = mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS; if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) { if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested; mInvalidateRootRequested = false ; mIsAnimating = false ; if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) { mHardwareYOffset = yOffset; mHardwareXOffset = xOffset; invalidateRoot = true ; } if (invalidateRoot) { mAttachInfo.mHardwareRenderer.invalidateRoot(); } dirty.setEmpty(); final boolean updated = updateContentDrawBounds(); if (mReportNextDraw) { mAttachInfo.mHardwareRenderer.setStopped(false ); } if (updated) { requestDrawWindow(); } mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this ); } else { if (mAttachInfo.mHardwareRenderer != null && !mAttachInfo.mHardwareRenderer.isEnabled() && mAttachInfo.mHardwareRenderer.isRequested()) { try { mAttachInfo.mHardwareRenderer.initializeIfNeeded( mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets); } catch (OutOfResourcesException e) { handleOutOfResourcesException(e); return ; } mFullRedrawNeeded = true ; scheduleTraversals(); return ; } if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) { return ; } } } if (animating) { mFullRedrawNeeded = true ; scheduleTraversals(); } }
核心逻辑是:
如果是硬件绘制,那就通过 mHardwareRenderer draw,这个是在 render 线程;
如果是软件绘制,那就通过 drawSoftware 触发 view draw,这个是在主线程;
2.6.2 drawSoftware - 软件绘制 软件绘制开始:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 private boolean drawSoftware (Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty) { final Canvas canvas; try { final int left = dirty.left; final int top = dirty.top; final int right = dirty.right; final int bottom = dirty.bottom; canvas = mSurface.lockCanvas(dirty); if (left != dirty.left || top != dirty.top || right != dirty.right || bottom != dirty.bottom) { attachInfo.mIgnoreDirtyState = true ; } canvas.setDensity(mDensity); } catch (Surface.OutOfResourcesException e) { handleOutOfResourcesException(e); return false ; } catch (IllegalArgumentException e) { Log.e(mTag, "Could not lock surface" , e); mLayoutRequested = true ; return false ; } try { if (DEBUG_ORIENTATION || DEBUG_DRAW) { Log.v(mTag, "Surface " + surface + " drawing to bitmap w=" + canvas.getWidth() + ", h=" + canvas.getHeight()); } if (!canvas.isOpaque() || yoff != 0 || xoff != 0 ) { canvas.drawColor(0 , PorterDuff.Mode.CLEAR); } dirty.setEmpty(); mIsAnimating = false ; mView.mPrivateFlags |= View.PFLAG_DRAWN; if (DEBUG_DRAW) { Context cxt = mView.getContext(); Log.i(mTag, "Drawing: package:" + cxt.getPackageName() + ", metrics=" + cxt.getResources().getDisplayMetrics() + ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo()); } try { canvas.translate(-xoff, -yoff); if (mTranslator != null ) { mTranslator.translateCanvas(canvas); } canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0 ); attachInfo.mSetIgnoreDirtyState = false ; mView.draw(canvas); drawAccessibilityFocusedDrawableIfNeeded(canvas); } finally { if (!attachInfo.mSetIgnoreDirtyState) { attachInfo.mIgnoreDirtyState = false ; } } } finally { try { surface.unlockCanvasAndPost(canvas); } catch (IllegalArgumentException e) { Log.e(mTag, "Could not unlock surface" , e); mLayoutRequested = true ; return false ; } if (LOCAL_LOGV) { Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost" ); } } return true ; }
核心逻辑:
锁定 canvas,并返回一个 Canvas,大小和 dirty 一样;
调用 DecorView 的 draw 方法开始绘制;
2-mid DecorView 2.1-mid onAttachedToWindow DecorView 复写了这个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Override protected void onAttachedToWindow () { super .onAttachedToWindow(); final Window.Callback cb = mWindow.getCallback(); if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0 ) { cb.onAttachedToWindow(); } if (mFeatureId == -1 ) mWindow.openPanelsAfterRestore(); } if (!mWindowResizeCallbacksAdded) { getViewRootImpl().addWindowCallbacks(this ); mWindowResizeCallbacksAdded = true ; } else if (mBackdropFrameRenderer != null ) { mBackdropFrameRenderer.onConfigurationChange(); } }
这里的核心逻辑是:
调用了 Activity.onAttachedToWindow 方法;
将 DecorView 作为 callback 注册到 ViewRootImpl 中;
3 ViewGroup 由于 DecorView 是一个 FlameLayout,所以其本质是一个 ViewGroup,对于 DecorView,其 parent 是 ViewRootImpl,他需要 attach 到 ViewRootImpl 上才行:
3.1 dispatchAttachedToWindow - 核心(设置 attrachInfo) 将 AttachInfo 设置到 ViewGroup 中,这个方法是从 DecorView 开始出发的!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Override void dispatchAttachedToWindow (AttachInfo info, int visibility) { mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW; super .dispatchAttachedToWindow(info, visibility); mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW; final int count = mChildrenCount; final View[] children = mChildren; for (int i = 0 ; i < count; i++) { final View child = children[i]; child.dispatchAttachedToWindow(info, combineVisibility(visibility, child.getVisibility())); } final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size(); for (int i = 0 ; i < transientCount; ++i) { View view = mTransientViews.get(i); view.dispatchAttachedToWindow(info, combineVisibility(visibility, view.getVisibility())); } }
可以看到,从 DecorView 开始对每一个 Child 都会 dispatchAttachedToWindow,将 mAttachInfo 设置进去;
3.2 dispatchWindowVisibilityChanged 分发窗口改变给所有的 child:
1 2 3 4 5 6 7 8 9 10 11 @Override public void dispatchWindowVisibilityChanged (int visibility) { super .dispatchWindowVisibilityChanged(visibility); final int count = mChildrenCount; final View[] children = mChildren; for (int i = 0 ; i < count; i++) { children[i].dispatchWindowVisibilityChanged(visibility); } }
3.3 dispatchVisibilityAggregated 执行可见性合并给所有的 child:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Override boolean dispatchVisibilityAggregated (boolean isVisible) { isVisible = super .dispatchVisibilityAggregated(isVisible); final int count = mChildrenCount; final View[] children = mChildren; for (int i = 0 ; i < count; i++) { if (children[i].getVisibility() == VISIBLE) { children[i].dispatchVisibilityAggregated(isVisible); } } return isVisible; }
4 View ViewGroup 的父类就是 View:
4.1 dispatchAttachedToWindow - 核心(设置 attrachInfo) 这里来看看 View 中的操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 void dispatchAttachedToWindow (AttachInfo info, int visibility) { mAttachInfo = info; if (mOverlay != null ) { mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); } mWindowAttachCount++; mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; if (mFloatingTreeObserver != null ) { info.mTreeObserver.merge(mFloatingTreeObserver); mFloatingTreeObserver = null ; } registerPendingFrameMetricsObservers(); if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0 ) { mAttachInfo.mScrollContainers.add(this ); mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; } if (mRunQueue != null ) { mRunQueue.executeActions(info.mHandler); mRunQueue = null ; } performCollectViewAttributes(mAttachInfo, visibility); onAttachedToWindow(); ListenerInfo li = mListenerInfo; final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = li != null ? li.mOnAttachStateChangeListeners : null ; if (listeners != null && listeners.size() > 0 ) { for (OnAttachStateChangeListener listener : listeners) { listener.onViewAttachedToWindow(this ); } } int vis = info.mWindowVisibility; if (vis != GONE) { onWindowVisibilityChanged(vis); if (isShown()) { onVisibilityAggregated(vis == VISIBLE); } } onVisibilityChanged(this , visibility); if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0 ) { refreshDrawableState(); } needGlobalAttributesUpdate(false ); }
我们来看看核心的流程:
将 AttachInfo info 保存到 View.mAttachInfo 中,表示已经绑定;
该 view 的 mWindowAttachCount 引用计数加 1,表示已经 attach 到了 window 上;
合并 view 的 TreeObserver 内部的监听接口到 info.mTreeObserver 中;
执行所有 View.post 添加的 Runnable 任务;
触发生命周期函数 onAttachedToWindow;
如果 view 通过 setOnAttachStateChangeListener 设置了监听器,触发其 OnAttachStateChangeListener.onViewAttachedToWindow 方法;
触发 view 生命周期 onWindowVisibilityChanged 方法;
触发 view 生命周期 onVisibilityChanged 方法;
其他的一些函数:
对于 onVisibilityChanged 方法,View 并没有实现具体的逻辑,参数 View changedView 表示可见变化的 view,可能是 view 自身,也可能是 view 的 parent;
1 2 protected void onVisibilityChanged (@NonNull View changedView, @Visibility int visibility) {}
刷新 Drawable State:
1 2 3 4 5 6 7 8 9 10 11 public void refreshDrawableState () { mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; drawableStateChanged(); ViewParent parent = mParent; if (parent != null ) { parent.childDrawableStateChanged(this ); } }
我们可以通过 getDrawableState 获取最新的 DrawableState;
needGlobalAttributesUpdate
用于判断是否需要更新全局属性,参数 force 表示是否强制更新:
1 2 3 4 5 6 7 8 9 10 void needGlobalAttributesUpdate (boolean force) { final AttachInfo ai = mAttachInfo; if (ai != null && !ai.mRecomputeGlobalAttributes) { if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0 ) || ai.mHasSystemUiListeners) { ai.mRecomputeGlobalAttributes = true ; } } }
整个我们先不关注。
4.1.1 registerPendingFrameMetricsObservers 1 2 3 4 5 6 7 8 9 10 11 12 private void registerPendingFrameMetricsObservers () { if (mFrameMetricsObservers != null ) { ThreadedRenderer renderer = getHardwareRenderer(); if (renderer != null ) { for (FrameMetricsObserver fmo : mFrameMetricsObservers) { renderer.addFrameMetricsObserver(fmo); } } else { Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats" ); } } }
收集 view 的属性到 attachInfo 中:
1 2 3 4 5 6 7 8 9 10 11 12 void performCollectViewAttributes (AttachInfo attachInfo, int visibility) { if ((visibility & VISIBILITY_MASK) == VISIBLE) { if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { attachInfo.mKeepScreenOn = true ; } attachInfo.mSystemUiVisibility |= mSystemUiVisibility; ListenerInfo li = mListenerInfo; if (li != null && li.mOnSystemUiVisibilityChangeListener != null ) { attachInfo.mHasSystemUiListeners = true ; } } }
4.1.3 onAttachedToWindow 生命周期回调,表示 attached 到了 window 上:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @CallSuper protected void onAttachedToWindow () { if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0 ) { mParent.requestTransparentRegion(this ); } mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; jumpDrawablesToCurrentState(); resetSubtreeAccessibilityStateChanged(); rebuildOutline(); if (isFocused()) { InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null ) { imm.focusIn(this ); } } }
注意,这里对于 DecorView 有一些不一样,DecorView 本质上也是一个 View,而它复写了这个方法;
4.1.4 onWindowVisibilityChanged 窗口可见性发生变化,回调整个方法:
1 2 3 4 5 6 protected void onWindowVisibilityChanged (@Visibility int visibility) { if (visibility == VISIBLE) { initialAwakenScrollBars(); } }
暂时不分析;
4.1.5 isShown 判断该 view 以及其所有的 parent view 是否都用户可见的;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public boolean isShown () { View current = this ; do { if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { return false ; } ViewParent parent = current.mParent; if (parent == null ) { return false ; } if (!(parent instanceof View)) { return true ; } current = (View) parent; } while (current != null ); return false ; }
这里的 mViewFlags 表示的用户指定可见性,就是通过 android:visibable 或者 view.seVisibable 指定的可见性;
4.1.5 onVisibilityAggregated isVisible 表示 window 是否是可见的;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @CallSuper public void onVisibilityAggregated (boolean isVisible) { if (isVisible && mAttachInfo != null ) { initialAwakenScrollBars(); } final Drawable dr = mBackground; if (dr != null && isVisible != dr.isVisible()) { dr.setVisible(isVisible, false ); } final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null ; if (fg != null && isVisible != fg.isVisible()) { fg.setVisible(isVisible, false ); } }
调整 Background Drawable 和 Foreground Drawable 的可见性;
4.2 dispatchWindowVisibilityChanged 响应窗口可见性变化:
1 2 3 4 public void dispatchWindowVisibilityChanged (@Visibility int visibility) { onWindowVisibilityChanged(visibility); }
不多说;
4.3 dispatchVisibilityAggregated 响应可见性调整:
1 2 3 4 5 6 7 8 9 10 boolean dispatchVisibilityAggregated (boolean isVisible) { final boolean thisVisible = getVisibility() == VISIBLE; if (thisVisible || !isVisible) { onVisibilityAggregated(isVisible); } return thisVisible && isVisible; }
4.4 MeasureSpec - 测量规格 MeasureSpec 是 View 的内部类。他表示一种测量规格,是父布局传递给子布局的布局要求。
4.4.1 测量模式
UNSPECIFIED :不对 View 大小做限制,例如:ListView,ScrollView
1 2 3 4 public static final int UNSPECIFIED = 0 << MODE_SHIFT;
EXACTLY :确切的大小,例如:100dp 或者 march_parent
1 2 3 4 public static final int EXACTLY = 1 << MODE_SHIFT;
AT_MOST :大小不可超过某数值,例如:wrap_content
1 2 3 4 public static final int AT_MOST = 2 << MODE_SHIFT;
4.4.2 makeMeasureSpec 根据提供的大小和模式创建度量规范:
1 2 3 4 5 6 7 8 9 10 public static int makeMeasureSpec (@IntRange(from = 0 , to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode) { if (sUseBrokenMakeMeasureSpec) { return size + mode; } else { return (size & ~MODE_MASK) | (mode & MODE_MASK); } }
我们知道,MeasureSpec 是 32 位的 Int 型,高两位表示 mode,低 30 位表示 size,这里的 MODE_MASK 的作用实际上就是做位操作!
MODE_MASK 取如下的值:
1 2 private static final int MODE_SHIFT = 30 ;private static final int MODE_MASK = 0x3 << MODE_SHIFT;
其中 0x3 是十六进制,转为二进制是 11,向左移位30,结果是 11000…..0000(一共 30 个 0)!
size & ~MODE_MASK:获取 size 的低 30 位;
mode & MODE_MASK:获取 mode 的高两位;
最终合成度量规格;
5 ViewTreeObserver - 视图树的观察者 前面我们有分析过 ViewTreeObserver 用来动态监听布局的变化;
5.1 merge 合并 observer 中的接口回调到当前的 ViewTreeObserver 中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 void merge (ViewTreeObserver observer) { if (observer.mOnWindowAttachListeners != null ) { if (mOnWindowAttachListeners != null ) { mOnWindowAttachListeners.addAll(observer.mOnWindowAttachListeners); } else { mOnWindowAttachListeners = observer.mOnWindowAttachListeners; } } if (observer.mOnWindowFocusListeners != null ) { if (mOnWindowFocusListeners != null ) { mOnWindowFocusListeners.addAll(observer.mOnWindowFocusListeners); } else { mOnWindowFocusListeners = observer.mOnWindowFocusListeners; } } if (observer.mOnGlobalFocusListeners != null ) { if (mOnGlobalFocusListeners != null ) { mOnGlobalFocusListeners.addAll(observer.mOnGlobalFocusListeners); } else { mOnGlobalFocusListeners = observer.mOnGlobalFocusListeners; } } if (observer.mOnGlobalLayoutListeners != null ) { if (mOnGlobalLayoutListeners != null ) { mOnGlobalLayoutListeners.addAll(observer.mOnGlobalLayoutListeners); } else { mOnGlobalLayoutListeners = observer.mOnGlobalLayoutListeners; } } if (observer.mOnPreDrawListeners != null ) { if (mOnPreDrawListeners != null ) { mOnPreDrawListeners.addAll(observer.mOnPreDrawListeners); } else { mOnPreDrawListeners = observer.mOnPreDrawListeners; } } if (observer.mOnTouchModeChangeListeners != null ) { if (mOnTouchModeChangeListeners != null ) { mOnTouchModeChangeListeners.addAll(observer.mOnTouchModeChangeListeners); } else { mOnTouchModeChangeListeners = observer.mOnTouchModeChangeListeners; } } if (observer.mOnComputeInternalInsetsListeners != null ) { if (mOnComputeInternalInsetsListeners != null ) { mOnComputeInternalInsetsListeners.addAll(observer.mOnComputeInternalInsetsListeners); } else { mOnComputeInternalInsetsListeners = observer.mOnComputeInternalInsetsListeners; } } if (observer.mOnScrollChangedListeners != null ) { if (mOnScrollChangedListeners != null ) { mOnScrollChangedListeners.addAll(observer.mOnScrollChangedListeners); } else { mOnScrollChangedListeners = observer.mOnScrollChangedListeners; } } if (observer.mOnWindowShownListeners != null ) { if (mOnWindowShownListeners != null ) { mOnWindowShownListeners.addAll(observer.mOnWindowShownListeners); } else { mOnWindowShownListeners = observer.mOnWindowShownListeners; } } observer.kill(); }
在将 mAttachInfo 设置到 view 去后,会将 view 自身设置的 ViewTreeObserver 的接口合并到 mAttachInfo.observer 中:
5.2 dispatchOnWindowAttachedChange 分发窗口绑定状态变化的消息:
1 2 3 4 5 6 7 8 9 10 11 12 13 final void dispatchOnWindowAttachedChange (boolean attached) { final CopyOnWriteArrayList<OnWindowAttachListener> listeners = mOnWindowAttachListeners; if (listeners != null && listeners.size() > 0 ) { for (OnWindowAttachListener listener : listeners) { if (attached) listener.onWindowAttached(); else listener.onWindowDetached(); } } }
onWindowAttached :绑定成功;
onWindowDetached :接触绑定;
5.3 dispatchOnTouchModeChanged 通知注册的收听者触摸模式已更改。
1 2 3 4 5 6 7 8 9 10 11 12 final void dispatchOnTouchModeChanged (boolean inTouchMode) { final CopyOnWriteArrayList<OnTouchModeChangeListener> listeners = mOnTouchModeChangeListeners; if (listeners != null && listeners.size() > 0 ) { for (OnTouchModeChangeListener listener : listeners) { listener.onTouchModeChanged(inTouchMode); } } }
参数表示是否 进入 / 退出 touch mode;
5.4 dispatchOnGlobalLayout 通知全局布局已经发生,在布局完成后会触发:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public final void dispatchOnGlobalLayout () { final CopyOnWriteArray<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners; if (listeners != null && listeners.size() > 0 ) { CopyOnWriteArray.Access<OnGlobalLayoutListener> access = listeners.start(); try { int count = access.size(); for (int i = 0 ; i < count; i++) { access.get(i).onGlobalLayout(); } } finally { listeners.end(); } } }
5.5 dispatchOnComputeInternalInsets 调用所有侦听器以计算当前插入边衬:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 final void dispatchOnComputeInternalInsets (InternalInsetsInfo inoutInfo) { final CopyOnWriteArray<OnComputeInternalInsetsListener> listeners = mOnComputeInternalInsetsListeners; if (listeners != null && listeners.size() > 0 ) { CopyOnWriteArray.Access<OnComputeInternalInsetsListener> access = listeners.start(); try { int count = access.size(); for (int i = 0 ; i < count; i++) { access.get(i).onComputeInternalInsets(inoutInfo); } } finally { listeners.end(); } } }
5.6 dispatchOnPreDraw 在 draw 之前会触发,用于取消回调:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @SuppressWarnings ("unchecked" )public final boolean dispatchOnPreDraw () { boolean cancelDraw = false ; final CopyOnWriteArray<OnPreDrawListener> listeners = mOnPreDrawListeners; if (listeners != null && listeners.size() > 0 ) { CopyOnWriteArray.Access<OnPreDrawListener> access = listeners.start(); try { int count = access.size(); for (int i = 0 ; i < count; i++) { cancelDraw |= !(access.get(i).onPreDraw()); } } finally { listeners.end(); } } return cancelDraw; }
6 Surface 相关 6.1 Surface ViewRootImpl 内部有一个 Surface 变量:
1 final Surface mSurface = new Surface();
6.1.1 new Surface 创建了一个空的 Surface 实例,其内部的数据会将在 readFromParcel 方法中填充:
1 2 3 4 public class Surface implements Parcelable { public Surface () { } }
其实就是 requestWindow 会回传数据;
6.1.2 getGenerationId 获得该 surface 关联的 id 标志,如果 native 层的 surface 变化的话,那么这个 id 值会增加;
1 2 3 4 5 public int getGenerationId () { synchronized (mLock) { return mGenerationId; } }
6.1.3 readFromParcel relayoutWindow 会将 Surface 数据跨进程传递过来,初始化客户端的 Surface,Surface 其实就是一个 Parcel:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public void readFromParcel (Parcel source) { if (source == null ) { throw new IllegalArgumentException("source must not be null" ); } synchronized (mLock) { mName = source.readString(); mIsSingleBuffered = source.readInt() != 0 ; setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source)); } }
7 总结 下面我们来通过 pic 看看整个过程的总结:
图先省略下。。。
遗留汇总 本篇文章木有跟踪和探究的很重要的源码:
View 相关 1 2 3 4 5 6 7 8 9 ViewGroup.measure(childWidthMeasureSpec, childHeightMeasureSpec); ViewGroup.layout(0 , 0 , host.getMeasuredWidth(), host.getMeasuredHeight()); View.requestFocus(View.FOCUS_FORWARD); view.requestLayout(); View.draw
Window 相关 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 mWindowSession = WindowManagerGlobal.getWindowSession(); res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel); int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params, (int ) (mView.getMeasuredWidth() * appScale + 0.5f ), (int ) (mView.getMeasuredHeight() * appScale + 0.5f ), viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0 , mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets, mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration, mSurface); mWindowSession.finishDrawing(mWindow);
Surface 相关