Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Layout Traversals (GDG Devfest 2014)

Lucas Rocha
November 15, 2014

Layout Traversals (GDG Devfest 2014)

Presented at GDG Devfest London 2014

Lucas Rocha

November 15, 2014
Tweet

More Decks by Lucas Rocha

Other Decks in Technology

Transcript

  1. CHOREOGRAPHER f1 f2 f3 f4 f5 . . . .

    . . VSYNC (60fps) Resize view Redraw view Input Events
  2. CHOREOGRAPHER public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {

    ... scheduleVsync(); ... } ... void doFrame(long frameTimeNanos, int frame) { ... if (!mFrameScheduled) { return; } ... doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); ... } Choreographer.java
  3. MEASURE * measure(int, int) f2 M M M M M

    M → onMeasure(int, int) measureHierarchy(...)
  4. LAYOUT * f2 M L M L M L M

    L M L M L layout(int, int, int, int) → onLayout(boolean, int, int, int, int) performLayout()
  5. DRAW * f2 M L D M L D M

    L D M L D M L D M L D draw(Canvas) → onDraw(Canvas) performDraw()
  6. requestLayout() public void requestLayout() { ... if (mParent != null

    && !mParent.isLayoutRequested()) { mParent.requestLayout(); } ... } void scheduleTraversals() { ... mTraversalBarrier = mHandler.getLooper().postSyncBarrier(); mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); ... } View.java ViewRootImpl.java
  7. invalidate(...) public void invalidateInternal(...) { ... mPrivateFlags |= PFLAG_DIRTY; ...

    if (mParent != null && mAttachInfo != null && l < r && t < b) { final Rect damage = mAttachInfo.mTmpInvalRect; damage.set(l, t, r, b); mParent.invalidateChild(this, damage); } ... } View.java
  8. postOnAnimation() public void postOnAnimation(Runnable action) { ... attachInfo.mViewRootImpl.mChoreographer.postCallback( Choreographer.CALLBACK_ANIMATION, action,

    null); ... } void doFrame(long frameTimeNanos, int frame) { ... doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); ... } View.java Choreographer.java
  9. LAZY MEASURE public final void measure(int widthMeasureSpec, int heightMeasureSpec) {

    ... int cacheIndex = mMeasureCache.indexOfKey(key); if (cacheIndex < 0 || sIgnoreMeasureCache) { onMeasure(widthMeasureSpec, heightMeasureSpec); mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } else { long value = mMeasureCache.valueAt(cacheIndex); setMeasuredDimensionRaw((int) (value >> 32), (int) value); mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } ... } View.java
  10. LAZY MEASURE public void layout(int l, int t, int r,

    int b) { if ((flags & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } ... } View.java
  11. BASIC TIPS 1. No layout requests during layout 2. No

    layout requests during animations 3. Invalidate regions when possible
  12. OnPreDrawListener // 1. Save layout state and wait for next

    frame. getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() { @Override public boolean onPreDraw() { getViewTreeObserver().removeOnPreDrawListener(this); // 2. Restore original layout state. // 3. Trigger animators towards new layout state. } }
  13. OVERRIDE VIEW METHODS public class DrawGreen extends Interceptor { private

    final Paint mPaint; public DrawGreen() { mPaint = new Paint(); mPaint.setColor(Color.GREEN); } @Override public void onDraw(View view, Canvas canvas) { canvas.drawPaint(mPaint); } }
  14. DEPLOY public final class MainActivity extends Activity { @Override protected

    void onCreate(Bundle savedInstanceState) { Probe.deploy(this, new DrawGreen(), new Filter.ViewId(R.id.view2)); super.onCreate(savedInstanceState); setContentView(R.id.main_activity); } }
  15. WRAP VIEW METHODS public class LogRequestLayout extends Interceptor { @Override

    public void requestLayout(View view) { super.requestLayout(view); Log.d(LOGTAG, “requestLayout() on ” + view); } }