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
580
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
540
Bringing Firefox to Android
lucasr
6
630
A Million Times Pattrn
lucasr
6
470
Mozilla & Mobile
lucasr
2
220
The State of Firefox Mobile
lucasr
1
2.2k
Other Decks in Technology
See All in Technology
IDperturb: Enhancing Variation in Synthetic Face Generation via Angular Perturbation
sansantech
PRO
0
130
AIで実装は速くなった。なのにプロダクトは速くならない。職能の壁を越えて価値のフローを設計する
nwiizo
6
6.7k
リージョンの壁を越える、 ちょっと変わったAWSサービスの話
falken
PRO
0
210
Bet AI Day 2026丨バクラク Autopilot、業務システムの再設計
layerx
PRO
2
1.1k
最新技術に積極チャレンジ!EKS共通基盤のこれまでとこれから
daitak
0
300
Bet AI Day 2026丨AIを「使う」から、AIが「働く」へ ― LayerXが進める「組織AI」の社会実装
layerx
PRO
2
2.1k
Self Healing Rollouts: Automating Production Fixes with Agentic AI
kdubois
0
150
推論の観測、できていますか? 〜 Google Cloud Gemini Enterprise Agent Platformで 3つの Gemini モデルを実測して踏んだ、評価の罠 〜
shukob
PRO
0
140
Benchmarking Vector Databases: pgvector vs. LanceDB
tsho
0
130
多摩川(.dev)ランニング入門 / Tamagawa.dev#3
fujiwara3
3
330
PM領域でのAI Agentの活用
lycorptech_jp
PRO
0
260
Hub & Spoke 環境のネットワークルーティングを分解してみる
tsuyataku
1
520
Featured
See All Featured
What's in a price? How to price your products and services
michaelherold
247
13k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
35
2.8k
Color Theory Basics | Prateek | Gurzu
gurzu
0
450
The Cost Of JavaScript in 2023
addyosmani
55
10k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.1k
Building AI with AI
inesmontani
PRO
1
1.2k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
430
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
260
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3k
From π to Pie charts
rasagy
0
350
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.9k
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