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
9
530
Layout Traversals (GDG Devfest 2014)
Presented at GDG Devfest London 2014
Lucas Rocha
November 15, 2014
Tweet
Share
More Decks by Lucas Rocha
See All by Lucas Rocha
Layout Traversals (Droidcon Turin 2015)
lucasr
16
600
Design-Engineering Workflow
lucasr
2
410
Custom Layouts
lucasr
34
2k
Introducing Smoothie
lucasr
7
510
Bringing Firefox to Android
lucasr
6
580
A Million Times Pattrn
lucasr
6
420
Mozilla & Mobile
lucasr
2
190
The State of Firefox Mobile
lucasr
1
2.1k
Other Decks in Technology
See All in Technology
With Devin -AIの自律とメンバーの自立
kotanin0
2
1k
[TechNight #91] Oracle Database 最新パフォーマンス分析手法
oracle4engineer
PRO
4
320
地域コミュニティへの「感謝」と「恩返し」 / 20250726jawsug-tochigi
kasacchiful
0
120
Claude CodeでKiroの仕様駆動開発を実現させるには...
gotalab555
1
170
クマ×共生 HACKATHON - 熊対策を『特別な行動」から「生活の一部」に -
pharaohkj
0
270
Strands Agents & Bedrock AgentCoreを1分でおさらい
minorun365
PRO
6
120
【Λ(らむだ)】最近のアプデ情報 / RPALT20250729
lambda
0
210
少人数でも回る! DevinとPlaybookで支える運用改善
ishikawa_pro
5
2.1k
データエンジニアがクラシルでやりたいことの現在地
gappy50
3
810
生成AI時代におけるAI・機械学習技術を用いたプロダクト開発の深化と進化 #BetAIDay
layerx
PRO
1
720
Microsoft Learn MCP/Fabric データエージェント/Fabric MCP/Copilot Studio-簡単・便利なAIエージェント作ってみた -"Building Simple and Powerful AI Agents with Microsoft Learn MCP, Fabric Data Agent, Fabric MCP, and Copilot Studio"-
reireireijinjin6
1
200
ビジネス文書に特化した基盤モデル開発 / SaaSxML_Session_2
sansan_randd
0
210
Featured
See All Featured
Bash Introduction
62gerente
613
210k
GraphQLとの向き合い方2022年版
quramy
49
14k
Become a Pro
speakerdeck
PRO
29
5.5k
Into the Great Unknown - MozCon
thekraken
40
1.9k
How to Think Like a Performance Engineer
csswizardry
25
1.8k
Building a Modern Day E-commerce SEO Strategy
aleyda
42
7.4k
Java REST API Framework Comparison - PWX 2021
mraible
31
8.7k
Scaling GitHub
holman
461
140k
Large-scale JavaScript Application Architecture
addyosmani
512
110k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
53
2.9k
Building Adaptive Systems
keathley
43
2.7k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
18
1k
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