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
570
9
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
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
660
Design-Engineering Workflow
lucasr
2
450
Custom Layouts
lucasr
34
2k
Introducing Smoothie
lucasr
7
530
Bringing Firefox to Android
lucasr
6
620
A Million Times Pattrn
lucasr
6
460
Mozilla & Mobile
lucasr
2
220
The State of Firefox Mobile
lucasr
1
2.2k
Other Decks in Technology
See All in Technology
Bill One 開発エンジニア 紹介資料
sansan33
PRO
7
19k
新しい SLO が良い感じにハマっている話
z63d
5
2.1k
ボトムアップ文化が強い組織で セキュリティをどう根付かせていくかの現在進行形の話 / Making Security Stick in a Bottom-Up Organization
yamaguchitk333
0
200
変化の早いClaude Codeを 書籍に落とし込む
oikon48
7
1.3k
ブラウザ研修 2026
recruitengineers
PRO
4
790
AI ネイティブな組織に Gemini Enterprise Agent Platform がなぜ必要なのか
asei
1
190
QAエンジニア起点で進める、SmartHRにおける信頼性向上について
kaomi_wombat
1
120
Service Connect 上のサービスに ECS Service の外側から到達できなかった話
ota1022
1
150
Forza Horizon 6 のテレメトリ機能で 自動運転に使えそうな学習データを集める話
henjin0
0
150
[しろおび夏祭り2026] チャットするAIから、作業するAIへ - 使われ方の変化と、その裏側で起きていること
kk0n
0
1.7k
サイバー捜査員研修(後半)
nomizone
1
810
AWS ネットワーク構築でハマった(ハマりかけた) 5選とそこから得た教訓
nagisa53
4
190
Featured
See All Featured
Practical Orchestrator
shlominoach
191
12k
ラッコキーワード サービス紹介資料
rakko
1
4.3M
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
890
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
650
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
66
57k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.3k
Making Projects Easy
brettharned
120
6.7k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
780
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.2k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
360
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.4k
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