コンコン゚」

コンコン゚」Share a Scribd company logo
Optymalizacja
hierarchii widokテウw na
platformie Android
Michaナ WナPdarczyk,
Mobilization 2015, ナテウdナコ
Jak tworzyト wydajne
aplikacje?
窶廰ayout Traversals on Android窶
Lucas Rocha
Facebook Inc.
DroidCon 2015, Berlin
Pozycjonowanie
Rysowanie
Interakcje ze zdarzeniami
Czym jest UI dla programisty?
Poczトtki Android窶兮 byナZ trudne ...
Przed Jelly Bean
ViewRoot.java
public final class ViewRoot extends Handler ... {
...
public void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
sendEmptyMessage(DO_TRAVERSAL);
}
}
...
public void handleMessage(Message msg) {
...
case DO_TRAVERSAL:
performTraversals();
...
}
}
Odナ孩ieナシanie ekranu
w przewidywalnych odstト冪ach czasu
Od Jelly Bean - Choreographer
... f1 f2 f3 f4 f5 ...
Resize
view
Redraw
view
Input
Events
Choreographer.java
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
ViewRootlmpl
ナトczy zarzトdcト okien z hierarchiト widokテウw
SurfaceFlinger
ViewRootImpl
Hierarchia widokテウw
Metody zwiトzane z widokami
Measure + Layout + Draw
measureHierarchy(...)
measure(int, int)
竊 onMeasure(int, int)
M M M
M M
M
*
Measure
Lazy Measure
Multi-MeasureSpec cache
View.java
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;
}
...
}
Lazy Measure
View.java
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;
}
...
}
Lazy Measure
RelativeLayout
LinearLayout Button
LinearLayout TextView
RelativeLayout RelativeLayout
TextView TextViewTextView TextView TextView TextView
requestLayout()
Multi-MeasureSpace cache
18 19
6.5 ms 0.7 ms
72 14
SDK
czas mierzenia
iloナ崙 wywoナBナ
Multi-MeasureSpace cache
layout(int, int, int, int) 竊 onLayout
(boolean, int, int, int, int)
M L M L M L
M L M L
M L
*
Layout
performLayout()
performDraw()
draw(Canvas)
竊 onDraw(Canvas)M L D
*
M L D M L DM L D
M L D M L D
Draw
View.java
private DisplayList getDisplayList(...) {
...
final HardwareCanvas canvas = displayList.start(width, height);
...
draw(canvas);
...
displayList.end();
...
}
Display List
Kiedy wykonywany jest layout(),
to na pewno zrobiony jest measure()
Kiedy wykonywany jest draw(),
to na pewno zrobiony jest layout()
Pamiト冲aj!
1. WywoナBnie getMeasured*() poza
onLayout()
2. Alokacja:
笳 onLayout(): Akceptowalna
笳 onMeasure(): Unikaト
笳 onDraw(): Nigdy
Unikaj!
Zmiany rozmiaru elementテウw,
odナ孩ieナシenie stanu, animacje
... f1 f2 f3 f4 f5 ...
Metoda requestLayout()
*
requestLayout()
View.java
public void requestLayout() {
...
if (mParent != null && !mParent.isLayoutRequested()) { mParent.
requestLayout();
}
...
}
ViewRootImpl.java
void scheduleTraversals() {
...
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
...
}
Metoda requestLayout()
Metoda invalidate()
... f1 f2 f3 f4 f5 ...
*
invalidate(...)
Metoda invalidate()
View.java
public void invalidateInternal(...) {
...
mPrivateFlags |= PFLAG_INVALIDATED;
...
if (mParent != null && mAttachInfo != null && l < r && t < b) {
final Rect damage = mAttachInfo.mTmpInvalRect;
damage.set(l, t, r, b);
mParent.invalidateChild(this, damage);
}
...
}
boolean draw(...) {
...
mRecreateDisplayList = (
mPrivateFlags & PFLAG_INVALIDATED) == PFLAG_INVALIDATED;
...
}
Metoda postOnAnimation()
...... f1 f2 f3 f4 f5 ...
*
postOnAmination()
valueAnimator
...
Metoda postOnAnimation()
View.java
public void postOnAnimation(Runnable action) {
...
attachInfo.mViewRootImpl.mChoreographer.postCallback(
Choreographer.CALLBACK_ANIMATION, action, null);
...
}
Choreographer.java
void doFrame(long frameTimeNanos, int frame) {
...
doCallbacks(Choreographer.CALLBACK_INPUT,frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_ANIMATION,frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_TRAVERSAL,frameTimeNanos);
...
}
Uナシywajmy OnPreDrawListener!
Tree Observer
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.
}
}
Nie wywoナVj layout() podczas layout
Nie wywoナVj layout() podczas animacji
WywoナVj invalidate() tylko na tych elementach,
ktテウre chcesz przerysowaト
Pamiト冲aj!
1. Prosta hierarchia widokテウw
2. Multi pass layout - unikajmy
Wydajnoナ崙
WナBsne widoki
1. Composite Views
2. Custom Composite Views
3. Flat Custom Views
WナBsne widoki
Przydatne narzト囘zia
Hierarchy Viewer
ナコrテウdナP: http://cfile10.uf.tistory.com/image/110412354E5A61652D1F2C
Stereovision Image Calculator
Stereovision Image Calculator
1. Menu zmienione z RelativeLayout
na FrameLayout
2. Uproszczenie hierarchii widokテウw
3. Wykres jako Custom Flat View
4. Kolejkowanie odナ孩ieナシania
Stereovision Image Calculator
Optymalizacja
Nexus 7
Nexus 7 po optymalizacja
Samsung Tab 2
Samsung tab 2 po optymalizacja
Stereovision Image Calculator
Wyniki optymalizacji
299.03
50.54
478.42
65.92
Czas renderowania [ms]
Po co tworzyト wydajne
aplikacje?
INFO@OPEN-RND.PL
QUESTIONS ? THOUGHTS ? COMMENTS ?
Feel free to contact us!
WWW.OPEN-RND.PL
Thank you
Michaナ WナPdarczyk
SENIOR SOFTWARE DEVELOPER of Open-RnD
michal.wlodarczyk@open-rnd.pl

More Related Content

Optymalizacja hierarchii widokoフ『 na platformie Android