Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Layout Traversals (GDG Devfest 2014)
Search
Lucas Rocha
November 15, 2014
Technology
560
9
Share
Layout Traversals (GDG Devfest 2014)
Presented at GDG Devfest London 2014
Lucas Rocha
November 15, 2014
More Decks by Lucas Rocha
See All by Lucas Rocha
Layout Traversals (Droidcon Turin 2015)
lucasr
16
630
Design-Engineering Workflow
lucasr
2
440
Custom Layouts
lucasr
34
2k
Introducing Smoothie
lucasr
7
520
Bringing Firefox to Android
lucasr
6
610
A Million Times Pattrn
lucasr
6
440
Mozilla & Mobile
lucasr
2
210
The State of Firefox Mobile
lucasr
1
2.2k
Other Decks in Technology
See All in Technology
20260428_Product Management Summit_tadokoroyoshiro
tadokoro_yoshiro
15
18k
フロントエンドの相手が変わった - AIが加わったWebの新しいインターフェース設計
azukiazusa1
31
9.7k
Shipping AI Agents — Lessons from Production
vvatanabe
0
320
Oracle Exadata Database Service on Cloud@Customer X11M (ExaDB-C@C) サービス概要
oracle4engineer
PRO
2
7.9k
「誰一人取り残されない」 AIエージェント時代のプロダクト設計思想 Product Management Summit 2026
mizushimac
1
2.8k
『生成AI時代のクレデンシャルとパーミッション設計 — Claude Code を起点に』の執筆企画
takuros
2
2.1k
AWS Transform CustomでIaCコードを自由自在に変換しよう
duelist2020jp
0
240
コードや知識を組み込む / Incorporate Code and Knowledge
ks91
PRO
0
210
試作とデモンストレーション / Prototyping and Demonstrations
ks91
PRO
0
170
「SaaSの次の時代」に重要性を増すステークホルダーマネジメントの要諦 ~解像度を圧倒的に高めPdMの価値を最大化させる方法~
kakehashi
PRO
3
3.6k
ハーネスエンジニアリング入門
knishioka
0
110
サービスの信頼性を高めるため、形骸化した「プロダクションミーティング」を立て直すまでの取り組み
stefafafan
1
220
Featured
See All Featured
What does AI have to do with Human Rights?
axbom
PRO
1
2.1k
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
390
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
210
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
180
Game over? The fight for quality and originality in the time of robots
wayneb77
1
170
Unsuck your backbone
ammeep
672
58k
Facilitating Awesome Meetings
lara
57
6.8k
Paper Plane (Part 1)
katiecoart
PRO
0
7k
Test your architecture with Archunit
thirion
1
2.2k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
1.9k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
130
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
160
Transcript
LAYOUT TRAVERSALS Devfest London, 2014
LUCAS ROCHA +LucasRocha | @lucasratmundo
None
BE DELIBERATE Less handwaviness in your UI code
UI TOOLKITS Layout + Rendering + Input Events
TICK TOCK VSYNC sets the pace.
CHOREOGRAPHER f1 f2 f3 f4 f5 . . . .
. . VSYNC (60fps) Resize view Redraw view Input Events
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
ViewRootImpl Connects WindowManager with the View framework
ViewRootImpl *
FRAMEWORK Measure + Layout + Draw
TRAVERSAL * performTraversals() f2 performTraversals()
MEASURE * measure(int, int) f2 M M M M M
M → onMeasure(int, int) measureHierarchy(...)
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()
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()
CHANGES Resize, redraw & animate.
* requestLayout() f1 f2 f3 f4 f5 . . .
. . .
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
* Invalidate(...) f1 f2 f3 f4 f5 . . .
. . .
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
* postOnAnimation() f1 f2 f3 f4 f5 . . .
. . . ValueAnimator ...
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
LAZY MEASURE Multi-MeasureSpec cache, invalidated in requestLayout()
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
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
BASIC TIPS 1. No layout requests during layout 2. No
layout requests during animations 3. Invalidate regions when possible
PERFORMANCE 1. Simplify your view hierarchy 2. Avoid multi-pass measurement
GO CUSTOM Simplify view hierarchy, performance, missing features. http://lucasr.org/?p=3920
TREE OBSERVER Use OnPreDrawListener!
TRANSITIONS http://lucasr.org/?p=3902
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. } }
PROBE IT! Intercept view methods. Dissect layout traversals. https://github.com/lucasr/probe
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); } }
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); } }
WRAP VIEW METHODS public class LogRequestLayout extends Interceptor { @Override
public void requestLayout(View view) { super.requestLayout(view); Log.d(LOGTAG, “requestLayout() on ” + view); } }
QUESTIONS? +LucasRocha | @lucasratmundo