Nuking nasty memory leaks Pierre-Yves Ricau Pierre-Yves Ricau - - PowerPoint PPT Presentation

nuking nasty memory leaks
SMART_READER_LITE
LIVE PREVIEW

Nuking nasty memory leaks Pierre-Yves Ricau Pierre-Yves Ricau - - PowerPoint PPT Presentation

LeakCanary Nuking nasty memory leaks Pierre-Yves Ricau Pierre-Yves Ricau dependencies { }A dependencies { debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5' releaseCompile


slide-1
SLIDE 1

Nuking nasty memory leaks

Pierre-Yves Ricau

LeakCanary

slide-2
SLIDE 2

Pierre-Yves Ricau

slide-3
SLIDE 3
slide-4
SLIDE 4
slide-5
SLIDE 5
slide-6
SLIDE 6
slide-7
SLIDE 7
slide-8
SLIDE 8

dependencies {
 }A

slide-9
SLIDE 9

dependencies {
 debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
 releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
 testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
 }A

slide-10
SLIDE 10

public class ExampleApplication extends Application {
 
 @Override public void onCreate() {
 super.onCreate();
 }A
 
 }B

slide-11
SLIDE 11

public class ExampleApplication extends Application {
 
 @Override public void onCreate() {
 super.onCreate();
 if (LeakCanary.isInAnalyzerProcess(this)) {
 return;
 }
 LeakCanary.install(this);
 }A
 
 }B

slide-12
SLIDE 12
slide-13
SLIDE 13
slide-14
SLIDE 14
slide-15
SLIDE 15
slide-16
SLIDE 16

public class NeoMobRealismView extends View {
 public NeoMobRealismView(Context context, AttributeSet attrs) {
 super(context, attrs);
 setBackgroundColor(getResources().getColor(R.color.ikb));
 }A
 
 @Override protected void onAttachedToWindow() {
 super.onAttachedToWindow();
 Application app = (Application) getContext().getApplicationContext();
 app.registerActivityLifecycleCallbacks(new LifecycleCallbacks() {
 
 @Override public void onActivityResumed(Activity activity) {
 animate().alpha(1);
 }B
 
 @Override public void onActivityPaused(Activity activity) {
 animate().alpha(0);
 }C
 });
 }D
 }E

slide-17
SLIDE 17

public class NeoMobRealismView extends View {
 public NeoMobRealismView(Context context, AttributeSet attrs) {
 super(context, attrs);
 setBackgroundColor(getResources().getColor(R.color.ikb));
 }A
 
 @Override protected void onAttachedToWindow() {
 super.onAttachedToWindow();
 Application app = (Application) getContext().getApplicationContext();
 app.registerActivityLifecycleCallbacks(new LifecycleCallbacks() {
 
 @Override public void onActivityResumed(Activity activity) {
 animate().alpha(1);
 }B
 
 @Override public void onActivityPaused(Activity activity) {
 animate().alpha(0);
 }C
 });
 }D
 }E

slide-18
SLIDE 18

public class NeoMobRealismView extends View {
 public NeoMobRealismView(Context context, AttributeSet attrs) {
 super(context, attrs);
 setBackgroundColor(getResources().getColor(R.color.ikb));
 }A
 
 @Override protected void onAttachedToWindow() {
 super.onAttachedToWindow();
 Application app = (Application) getContext().getApplicationContext();
 app.registerActivityLifecycleCallbacks(new LifecycleCallbacks() {
 
 @Override public void onActivityResumed(Activity activity) {
 animate().alpha(1);
 }B
 
 @Override public void onActivityPaused(Activity activity) {
 animate().alpha(0);
 }C
 });
 }D
 }E

slide-19
SLIDE 19

public class NeoMobRealismView extends View {
 public NeoMobRealismView(Context context, AttributeSet attrs) {
 super(context, attrs);
 setBackgroundColor(getResources().getColor(R.color.ikb));
 }A
 
 @Override protected void onAttachedToWindow() {
 super.onAttachedToWindow();
 Application app = (Application) getContext().getApplicationContext();
 app.registerActivityLifecycleCallbacks(new LifecycleCallbacks() {
 
 @Override public void onActivityResumed(Activity activity) {
 animate().alpha(1);
 }B
 
 @Override public void onActivityPaused(Activity activity) {
 animate().alpha(0);
 }C
 });
 }D
 }E

slide-20
SLIDE 20

public class NeoMobRealismView extends View {
 public NeoMobRealismView(Context context, AttributeSet attrs) {
 super(context, attrs);
 setBackgroundColor(getResources().getColor(R.color.ikb));
 }A
 
 @Override protected void onAttachedToWindow() {
 super.onAttachedToWindow();
 Application app = (Application) getContext().getApplicationContext();
 app.registerActivityLifecycleCallbacks(new LifecycleCallbacks() {
 
 @Override public void onActivityResumed(Activity activity) {
 animate().alpha(1);
 }B
 
 @Override public void onActivityPaused(Activity activity) {
 animate().alpha(0);
 }C
 });
 }D
 }E private LifecycleCallbacks callbacks;
 private final Application app;

slide-21
SLIDE 21

public class NeoMobRealismView extends View {
 
 private LifecycleCallbacks callbacks;
 private final Application app;
 
 public NeoMobRealismView(Context context, AttributeSet attrs) {…}
 
 @Override protected void onAttachedToWindow() {
 super.onAttachedToWindow();
 
 callbacks = new LifecycleCallbacks() {…};
 app.registerActivityLifecycleCallbacks(callbacks);
 }D
 
 @Override protected void onDetachedFromWindow() {
 super.onDetachedFromWindow();
 app.unregisterActivityLifecycleCallbacks(callbacks);
 }F
 }E

slide-22
SLIDE 22
slide-23
SLIDE 23
slide-24
SLIDE 24
slide-25
SLIDE 25
slide-26
SLIDE 26

class A {
 }

slide-27
SLIDE 27

class A {
 } class B {
 }

slide-28
SLIDE 28

class A {
 } class B {
 } class C {
 }

slide-29
SLIDE 29

class A {
 } class B {
 } class C {
 } static void triumvirate() {
 A a = new A();
 }

slide-30
SLIDE 30

class A {
 } class B {
 } class C {
 } static void triumvirate() {
 A a = new A();
 }

slide-31
SLIDE 31

class A {
 } class B {
 } class C {
 } static void triumvirate() {
 A a = new A();
 }B

slide-32
SLIDE 32

class A {
 } class B {
 } class C {
 } static void triumvirate() {
 A a = new A();
 B b = new B();
 }B

slide-33
SLIDE 33

class A {
 } class B {
 } class C {
 } static void triumvirate() {
 A a = new A();
 B b = new B();
 C c = new C();
 }B

slide-34
SLIDE 34

class A {
 B b;
 } class B {
 } class C {
 } static void triumvirate() {
 A a = new A();
 B b = new B();
 C c = new C();
 }B

slide-35
SLIDE 35

class A {
 B b;
 } class B {
 C c;
 } class C {
 } static void triumvirate() {
 A a = new A();
 B b = new B();
 C c = new C();
 }

slide-36
SLIDE 36

class A {
 B b;
 } class B {
 C c;
 } class C {
 A a;
 } static void triumvirate() {
 A a = new A();
 B b = new B();
 C c = new C();
 }

slide-37
SLIDE 37

class A {
 B b;
 } class B {
 C c;
 } class C {
 A a;
 } static void triumvirate() {
 A a = new A();
 B b = new B();
 C c = new C();
 a.b = b;
 }

slide-38
SLIDE 38

class A {
 B b;
 } class B {
 C c;
 } class C {
 A a;
 } static void triumvirate() {
 A a = new A();
 B b = new B();
 C c = new C();
 a.b = b;
 b.c = c;
 }

slide-39
SLIDE 39

class A {
 B b;
 } class B {
 C c;
 } class C {
 A a;
 } static void triumvirate() {
 A a = new A();
 B b = new B();
 C c = new C();
 a.b = b;
 b.c = c;
 c.a = a;
 }

slide-40
SLIDE 40

class A {
 B b;
 } class B {
 C c;
 } class C {
 A a;
 } static void triumvirate() {
 A a = new A();
 B b = new B();
 C c = new C();
 a.b = b;
 b.c = c;
 c.a = a;
 }

slide-41
SLIDE 41

class A {
 B b;
 } class B {
 C c;
 } class C {
 A a;
 } static void triumvirate() {
 A a = new A();
 B b = new B();
 C c = new C();
 a.b = b;
 b.c = c;
 c.a = a;
 }

slide-42
SLIDE 42

class A {
 B b;
 } class B {
 C c;
 } class C {
 A a;
 } static void triumvirate() {
 A a = new A();
 B b = new B();
 C c = new C();
 a.b = b;
 b.c = c;
 c.a = a;
 }

slide-43
SLIDE 43

class A {
 B b;
 } class B {
 C c;
 } class C {
 A a;
 } static void triumvirate() {
 A a = new A();
 B b = new B();
 C c = new C();
 a.b = b;
 b.c = c;
 c.a = a;
 } static A singleton

slide-44
SLIDE 44

class A {
 B b;
 } class B {
 C c;
 } class C {
 A a;
 } static void triumvirate() {
 A a = new A();
 B b = new B();
 C c = new C();
 a.b = b;
 b.c = c;
 c.a = a;
 singleton = a;
 } static A singleton

slide-45
SLIDE 45

class A {
 B b;
 } class B {
 C c;
 } class C {
 A a;
 } static void triumvirate() {
 A a = new A();
 B b = new B();
 C c = new C();
 a.b = b;
 b.c = c;
 c.a = a;
 singleton = a;
 } static A singleton

slide-46
SLIDE 46
slide-47
SLIDE 47
slide-48
SLIDE 48
slide-49
SLIDE 49
slide-50
SLIDE 50

class Activity {
 boolean mDestroyed = true;
 }

slide-51
SLIDE 51
slide-52
SLIDE 52
slide-53
SLIDE 53
slide-54
SLIDE 54
slide-55
SLIDE 55
slide-56
SLIDE 56
slide-57
SLIDE 57
slide-58
SLIDE 58
slide-59
SLIDE 59
slide-60
SLIDE 60
slide-61
SLIDE 61

public class NeoMobRealismView extends View {
 public NeoMobRealismView(Context context, AttributeSet attrs) {
 super(context, attrs);
 setBackgroundColor(getResources().getColor(R.color.ikb));
 }
 
 @Override protected void onAttachedToWindow() {
 super.onAttachedToWindow();
 Application app = (Application) getContext().getApplicationContext();
 app.registerActivityLifecycleCallbacks(new LifecycleCallbacks() {
 
 @Override public void onActivityResumed(Activity activity) {
 animate().alpha(1);
 }
 
 @Override public void onActivityPaused(Activity activity) {
 animate().alpha(0);
 }
 });
 }
 }

slide-62
SLIDE 62

class NeoMobRealismView$1 extends LifecycleCallbacks {
 
 private final NeoMobRealismView this$0;
 
 public NeoMobRealismView$1(NeoMobRealismView this$0) {
 this.this$0 = this$0;
 }
 
 @Override public void onActivityResumed(Activity activity) {
 this$0.animate().alpha(1);
 }
 
 @Override public void onActivityPaused(Activity activity) {
 this$0.animate().alpha(0);
 }
 } public class NeoMobRealismView extends View {
 public NeoMobRealismView(Context context, AttributeSet attrs) {
 super(context, attrs);
 setBackgroundColor(getResources().getColor(R.color.ikb));


slide-63
SLIDE 63
slide-64
SLIDE 64
slide-65
SLIDE 65
slide-66
SLIDE 66
slide-67
SLIDE 67
slide-68
SLIDE 68
slide-69
SLIDE 69

In com.example.leakcanary:1.0:1. * com.example.leakcanary.MainActivity has leaked: * GC ROOT static android.app.ActivityThread.sCurrentActivityThread * references android.app.ActivityThread.mInitialApplication * references com.example.leakcanary.ExampleApplication.mActivityLifecycleCallbacks * references java.util.ArrayList.elementData * references array java.lang.Object[].[5] * references com.example.leakcanary.NeoMobRealismView$1.this$0 (anonymous subclass of com.example.leakcanary.ActivityLifecycleCallbacksAdapter) * references com.example.leakcanary.NeoMobRealismView.mContext * leaks com.example.leakcanary.MainActivity instance * Retaining: 673 B. * Reference Key: 8b2e09ef-1ea7-48da-b09e-7bf337f64473 * Device: LGE google Nexus 5X bullhead * Android Version: 7.0 API: 24 LeakCanary: 1.6-SNAPSHOT 050b554 * Durations: watch=1296983ms, gc=210ms, heap dump=33311ms, analysis=125485ms * Details: * Class android.app.ActivityThread | static DEBUG_BROADCAST = false | static TWO_COUNT_COLUMNS = java.lang.String@1873829608 (0x6fb05ee8) | static sCurrentActivityThread = android.app.ActivityThread@851460352 (0x32c04100) | static DEBUG_BACKUP = false

slide-70
SLIDE 70

* Details: * Class android.app.ActivityThread | static DEBUG_BROADCAST = false | static TWO_COUNT_COLUMNS = java.lang.String@1873829608 (0x6fb05ee8) | static sCurrentActivityThread = android.app.ActivityThread@851460352 (0x32c04100) | static DEBUG_BACKUP = false | static LOG_AM_ON_RESUME_CALLED = 30022 | static DEBUG_RESULTS = false | static LOG_AM_ON_STOP_CALLED = 30049 | static ONE_COUNT_COLUMN_HEADER = java.lang.String@1873816328 (0x6fb02b08) | static DEBUG_ORDER = false | static sPackageManager = android.content.pm.IPackageManager$Stub$Proxy@851448320 (0x32c01200) | static THUMBNAIL_FORMAT = android.graphics.Bitmap$Config@1879418296 (0x7005a5b8) | static SERVICE_DONE_EXECUTING_START = 1 | static REPORT_TO_ACTIVITY = true | static DEBUG_MEMORY_TRIM = false | static ACTIVITY_THREAD_CHECKIN_VERSION = 4 | static HEAP_COLUMN = java.lang.String@1873840320 (0x6fb088c0) | static $classOverhead = byte[1223]@1879556985 (0x7007c379) | static SERVICE_DONE_EXECUTING_STOP = 2 | static HEAP_FULL_COLUMN = java.lang.String@1873843888 (0x6fb096b0) | static SERVICE_DONE_EXECUTING_ANON = 0

slide-71
SLIDE 71

| [14] = null * Instance of com.example.leakcanary.NeoMobRealismView$1 | static $classOverhead = byte[664]@851688449 (0x32c3bc01) | this$0 = com.example.leakcanary.NeoMobRealismView@852252560 (0x32cc5790) | shadow$_klass_ = com.example.leakcanary.NeoMobRealismView$1 | shadow$_monitor_ = 0 * Instance of com.example.leakcanary.NeoMobRealismView | static $classOverhead = byte[6184]@851804161 (0x32c58001) | mAccessibilityCursorPosition = -1 | mAccessibilityDelegate = null | mAccessibilityTraversalAfterId = -1 | mAccessibilityTraversalBeforeId = -1 | mAccessibilityViewId = -1 | mAnimator = android.view.ViewPropertyAnimator@852248440 (0x32cc4778) | mAttachInfo = null | mAttributes = null | mBackground = android.graphics.drawable.ColorDrawable@852305184 (0x32cd2520) | mBackgroundRenderNode = android.view.RenderNode@852339848 (0x32cdac88) | mBackgroundResource = 0 | mBackgroundSizeChanged = false | mBackgroundTint = null | mBottom = 1098 | mCachingFailed = false | mClipBounds = null

slide-72
SLIDE 72

| [14] = null * Instance of com.example.leakcanary.NeoMobRealismView$1 | static $classOverhead = byte[664]@851688449 (0x32c3bc01) | this$0 = com.example.leakcanary.NeoMobRealismView@852252560 (0x32cc5790) | shadow$_klass_ = com.example.leakcanary.NeoMobRealismView$1 | shadow$_monitor_ = 0 * Instance of com.example.leakcanary.NeoMobRealismView | static $classOverhead = byte[6184]@851804161 (0x32c58001) | mAccessibilityCursorPosition = -1 | mAccessibilityDelegate = null | mAccessibilityTraversalAfterId = -1 | mAccessibilityTraversalBeforeId = -1 | mAccessibilityViewId = -1 | mAnimator = android.view.ViewPropertyAnimator@852248440 (0x32cc4778) | mAttachInfo = null | mAttributes = null | mBackground = android.graphics.drawable.ColorDrawable@852305184 (0x32cd2520) | mBackgroundRenderNode = android.view.RenderNode@852339848 (0x32cdac88) | mBackgroundResource = 0 | mBackgroundSizeChanged = false | mBackgroundTint = null | mBottom = 1098 | mCachingFailed = false | mClipBounds = null

slide-73
SLIDE 73

public class View {
 
 AttachInfo mAttachInfo;
 
 public boolean isAttachedToWindow() {
 return mAttachInfo != null;
 } }

slide-74
SLIDE 74
slide-75
SLIDE 75
slide-76
SLIDE 76
slide-77
SLIDE 77
slide-78
SLIDE 78

StackTraceElement[] stackTrace = {
 new StackTraceElement("com.foo.Foo", "bakeBaguette", "Foo.java", 42),
 new StackTraceElement("com.foo.Bar", "bailarLaBamba", "Bar.java", 7),
 };
 RuntimeException exception = new RuntimeException();
 exception.setStackTrace(stackTrace);

slide-79
SLIDE 79

public final class BugsnagLeakUploader {
 
 public BugsnagLeakUploader() {…}
 
 public void uploadLeak(AnalysisResult result, String leakInfo) {
 Throwable t = exception(result.className, result.leakTrace);
 bugsnagClient.notify(t, Severity.WARNING, metadata);
 }
 
 private RuntimeException exception(String className, LeakTrace trace) {…}
 
 }

slide-80
SLIDE 80
slide-81
SLIDE 81
slide-82
SLIDE 82
slide-83
SLIDE 83
slide-84
SLIDE 84
slide-85
SLIDE 85

public final class ViewRootImpl { static final class RunQueue {
 private final ArrayList<HandlerAction> mActions = new ArrayList<>();
 void post(Runnable action) {
 postDelayed(action, 0);
 }A
 
 void postDelayed(Runnable action, long delayMillis) {
 HandlerAction handlerAction = new HandlerAction();
 handlerAction.action = action;
 handlerAction.delay = delayMillis;
 
 synchronized (mActions) {
 mActions.add(handlerAction);
 }B
 }C }D }E

slide-86
SLIDE 86

public final class ViewRootImpl { static final class RunQueue {
 private final ArrayList<HandlerAction> mActions = new ArrayList<>();
 void post(Runnable action) {
 postDelayed(action, 0);
 }A
 
 void postDelayed(Runnable action, long delayMillis) {
 HandlerAction handlerAction = new HandlerAction();
 handlerAction.action = action;
 handlerAction.delay = delayMillis;
 
 synchronized (mActions) {
 mActions.add(handlerAction);
 }B
 }C }D }E

slide-87
SLIDE 87

public final class ViewRootImpl { static final class RunQueue {
 private final ArrayList<HandlerAction> mActions = new ArrayList<>();
 void post(Runnable action) {
 postDelayed(action, 0);
 }A
 
 void postDelayed(Runnable action, long delayMillis) {
 HandlerAction handlerAction = new HandlerAction();
 handlerAction.action = action;
 handlerAction.delay = delayMillis;
 
 synchronized (mActions) {
 mActions.add(handlerAction);
 }B
 }C }D }E

slide-88
SLIDE 88

public final class ViewRootImpl { static final class RunQueue {
 private final ArrayList<HandlerAction> mActions = new ArrayList<>();
 void post(Runnable action) {
 postDelayed(action, 0);
 }A
 
 void postDelayed(Runnable action, long delayMillis) {
 HandlerAction handlerAction = new HandlerAction();
 handlerAction.action = action;
 handlerAction.delay = delayMillis;
 
 synchronized (mActions) {
 mActions.add(handlerAction);
 }B
 }C }D }EE

slide-89
SLIDE 89

public final class ViewRootImpl { /**
 * The run queue is used to enqueue pending work from Views when no Handler
 * is attached. The work is executed during the next call to
 * performTraversals on the thread.
 */ static final class RunQueue {
 private final ArrayList<HandlerAction> mActions = new ArrayList<>();
 void post(Runnable action) {
 postDelayed(action, 0);
 }A
 
 void postDelayed(Runnable action, long delayMillis) {
 HandlerAction handlerAction = new HandlerAction();
 handlerAction.action = action;
 handlerAction.delay = delayMillis;
 
 synchronized (mActions) {
 mActions.add(handlerAction);
 }B
 }C

slide-90
SLIDE 90

public final class ViewRootImpl { /**
 * The run queue is used to enqueue pending work from Views when no Handler
 * is attached. The work is executed during the next call to
 * performTraversals on the thread.
 */ static final class RunQueue {
 private final ArrayList<HandlerAction> mActions = new ArrayList<>();
 void post(Runnable action) {
 postDelayed(action, 0);
 }A
 
 void postDelayed(Runnable action, long delayMillis) {
 HandlerAction handlerAction = new HandlerAction();
 handlerAction.action = action;
 handlerAction.delay = delayMillis;
 
 synchronized (mActions) {
 mActions.add(handlerAction);
 }B
 }C

slide-91
SLIDE 91

public class View { public void postOnAnimation(Runnable action) {
 AttachInfo attachInfo = mAttachInfo;
 if (attachInfo != null) {
 attachInfo.mViewRootImpl.mChoreographer.postCallback(
 Choreographer.CALLBACK_ANIMATION, action, null);
 } else {
 ViewRootImpl.getRunQueue().post(action);
 }A
 }B public boolean post(Runnable action) {
 final AttachInfo attachInfo = mAttachInfo;
 if (attachInfo != null) {
 return attachInfo.mHandler.post(action);
 }E
 ViewRootImpl.getRunQueue().post(action);
 return true;
 }C }D

slide-92
SLIDE 92

public class View { public void postOnAnimation(Runnable action) {
 AttachInfo attachInfo = mAttachInfo;
 if (attachInfo != null) {
 attachInfo.mViewRootImpl.mChoreographer.postCallback(
 Choreographer.CALLBACK_ANIMATION, action, null);
 } else {
 ViewRootImpl.getRunQueue().post(action);
 }A
 }B public boolean post(Runnable action) {
 final AttachInfo attachInfo = mAttachInfo;
 if (attachInfo != null) {
 return attachInfo.mHandler.post(action);
 }E
 ViewRootImpl.getRunQueue().post(action);
 return true;
 }C }D

slide-93
SLIDE 93

public class View { public void postOnAnimation(Runnable action) {
 AttachInfo attachInfo = mAttachInfo;
 if (attachInfo != null) {
 attachInfo.mViewRootImpl.mChoreographer.postCallback(
 Choreographer.CALLBACK_ANIMATION, action, null);
 } else {
 ViewRootImpl.getRunQueue().post(action);
 }A
 }B public boolean post(Runnable action) {
 final AttachInfo attachInfo = mAttachInfo;
 if (attachInfo != null) {
 return attachInfo.mHandler.post(action);
 }E
 ViewRootImpl.getRunQueue().post(action);
 return true;
 }C }D

slide-94
SLIDE 94

public class View { public void postOnAnimation(Runnable action) {
 AttachInfo attachInfo = mAttachInfo;
 if (attachInfo != null) {
 attachInfo.mViewRootImpl.mChoreographer.postCallback(
 Choreographer.CALLBACK_ANIMATION, action, null);
 } else {
 ViewRootImpl.getRunQueue().post(action);
 }A
 }B public boolean post(Runnable action) {
 final AttachInfo attachInfo = mAttachInfo;
 if (attachInfo != null) {
 return attachInfo.mHandler.post(action);
 }E
 ViewRootImpl.getRunQueue().post(action);
 return true;
 }C }D

slide-95
SLIDE 95

public final class ViewRootImpl { 
 static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<>(); static RunQueue getRunQueue() {
 RunQueue queue = sRunQueues.get();
 if (queue != null) {
 return queue;
 }A
 queue = new RunQueue();
 sRunQueues.set(queue);
 return queue;
 }B }C

slide-96
SLIDE 96

public final class ViewRootImpl { 
 static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<>(); static RunQueue getRunQueue() {
 RunQueue queue = sRunQueues.get();
 if (queue != null) {
 return queue;
 }A
 queue = new RunQueue();
 sRunQueues.set(queue);
 return queue;
 }B }C

slide-97
SLIDE 97

public final class ViewRootImpl { 
 static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<>(); static RunQueue getRunQueue() {
 RunQueue queue = sRunQueues.get();
 if (queue != null) {
 return queue;
 }A
 queue = new RunQueue();
 sRunQueues.set(queue);
 return queue;
 }B }C

slide-98
SLIDE 98

public final class ViewRootImpl { 
 static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<>(); static RunQueue getRunQueue() {
 RunQueue queue = sRunQueues.get();
 if (queue != null) {
 return queue;
 }A
 queue = new RunQueue();
 sRunQueues.set(queue);
 return queue;
 }B }C

slide-99
SLIDE 99
slide-100
SLIDE 100
slide-101
SLIDE 101
slide-102
SLIDE 102
slide-103
SLIDE 103

public class AppCompatActivity extends FragmentActivity { private AppCompatDelegate mDelegate; @Override
 protected void onDestroy() {
 super.onDestroy();
 getDelegate().onDestroy();
 } public AppCompatDelegate getDelegate() {
 if (mDelegate == null) {
 mDelegate = AppCompatDelegate.create(this, this);
 }
 return mDelegate;
 } }

slide-104
SLIDE 104
slide-105
SLIDE 105
slide-106
SLIDE 106
slide-107
SLIDE 107

class AppCompatDelegateImplV9 { private final Runnable mInvalidatePanelMenuRunnable = new Runnable() {
 @Override
 public void run() {…}
 }; private void invalidatePanelMenu(int featureId) {
 mWindowDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
 } 
 }

slide-108
SLIDE 108

class AppCompatDelegateImplV9 { private final Runnable mInvalidatePanelMenuRunnable = new Runnable() {
 @Override
 public void run() {…}
 }; private void invalidatePanelMenu(int featureId) {
 mWindowDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
 } 
 }

slide-109
SLIDE 109

class AppCompatDelegateImplV9 { private final Runnable mInvalidatePanelMenuRunnable = new Runnable() {
 @Override
 public void run() {…}
 }; private void invalidatePanelMenu(int featureId) {
 mWindowDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
 } @Override
 public void onDestroy() { super.onDestroy();
 mWindowDecor.removeCallbacks(mInvalidatePanelMenuRunnable);
 }
 


slide-110
SLIDE 110
slide-111
SLIDE 111
slide-112
SLIDE 112
slide-113
SLIDE 113
slide-114
SLIDE 114

* Instance of com.squareup.ui.permissions.PasscodeUnlockView | mAccessibilityCursorPosition = -1 | mAccessibilityDelegate = null | mAccessibilityTraversalAfterId = -1 | mAccessibilityTraversalBeforeId = -1 | mAccessibilityViewId = -1 | mAnimator = null | mAttachInfo = null | mAttributes = null | mBackground = android.graphics.drawable.ColorDrawable@328049760 (0x138da460) | mBackgroundRenderNode = android.view.RenderNode@338685248 (0x142fed40) | mBackgroundResource = 0 | mBackgroundSizeChanged = false | mBackgroundTint = null | mBottom = 1731 | mCachingFailed = false | mClipBounds = null | mContentDescription = null

slide-115
SLIDE 115

* Instance of com.squareup.ui.permissions.PasscodeUnlockView | mAccessibilityCursorPosition = -1 | mAccessibilityDelegate = null | mAccessibilityTraversalAfterId = -1 | mAccessibilityTraversalBeforeId = -1 | mAccessibilityViewId = -1 | mAnimator = null | mAttachInfo = null | mAttributes = null | mBackground = android.graphics.drawable.ColorDrawable@328049760 (0x138da460) | mBackgroundRenderNode = android.view.RenderNode@338685248 (0x142fed40) | mBackgroundResource = 0 | mBackgroundSizeChanged = false | mBackgroundTint = null | mBottom = 1731 | mCachingFailed = false | mClipBounds = null | mContentDescription = null

slide-116
SLIDE 116
slide-117
SLIDE 117
slide-118
SLIDE 118
slide-119
SLIDE 119

public class PasscodeUnlockView extends FrameLayout { void setBackgroundImage(final RequestCreator request) {
 Views.waitForMeasure(merchantImage, new Views.OnMeasuredCallback() {
 @Override public void onMeasured(View view, int width, int height) {
 request.into(merchantImage, new Callback() {
 @Override public void onSuccess() {…}
 @Override public void onError() {…}
 });
 }
 }); } }

slide-120
SLIDE 120

public class PasscodeUnlockView extends FrameLayout { void setBackgroundImage(final RequestCreator request) {
 Views.waitForMeasure(merchantImage, new Views.OnMeasuredCallback() {
 @Override public void onMeasured(View view, int width, int height) {
 request.into(merchantImage, new Callback() {
 @Override public void onSuccess() {…}
 @Override public void onError() {…}
 });
 }
 }); } }

slide-121
SLIDE 121
slide-122
SLIDE 122
slide-123
SLIDE 123
slide-124
SLIDE 124
slide-125
SLIDE 125

public class PasscodeUnlockView extends FrameLayout { @Override protected void onDetachedFromWindow() {
 super.onDetachedFromWindow(); picasso.cancelRequest(merchantImage);
 } }

slide-126
SLIDE 126

public class Picasso { final Map<Object, Action> targetToAction; public void cancelRequest(ImageView target) {
 Action action = targetToAction.remove(target);
 if (action != null) {
 action.cancel();
 dispatcher.dispatchCancel(action);
 }
 if (target instanceof ImageView) {…} } }

slide-127
SLIDE 127

public class Picasso { final Map<Object, Action> targetToAction; public void cancelRequest(ImageView target) {
 Action action = targetToAction.remove(target);
 if (action != null) {
 action.cancel();
 dispatcher.dispatchCancel(action);
 }
 if (target instanceof ImageView) {…} } }

slide-128
SLIDE 128

public class Picasso { final Map<Object, Action> targetToAction; public void cancelRequest(ImageView target) {
 Action action = targetToAction.remove(target);
 if (action != null) {
 action.cancel();
 dispatcher.dispatchCancel(action);
 }
 if (target instanceof ImageView) {…} } }

slide-129
SLIDE 129

abstract class Action<T> { boolean cancelled; void cancel() {
 cancelled = true;
 } }

slide-130
SLIDE 130

* Instance of com.squareup.picasso.ImageViewAction | callback = com.squareup.ui.permissions.PasscodeUnlockView$4$1@338661168 (0x142f8f30) | cancelled = false | errorDrawable = null | errorResId = 0 | key = java.lang.String@316241360 (0x12d975d0) | memoryPolicy = 0 | networkPolicy = 0 | noFade = false | picasso = com.squareup.picasso.Picasso@333016576 (0x13d96e00) | request = com.squareup.picasso.Request@338645408 (0x142f51a0) | tag = com.squareup.picasso.ImageViewAction@338500224 (0x142d1a80) | target = com.squareup.picasso.Action$RequestWeakReference@338684128 (0x142fe8e0) | willReplay = false | shadow$_klass_ = com.squareup.picasso.ImageViewAction | shadow$_monitor_ = -2047389420

slide-131
SLIDE 131

* Instance of com.squareup.picasso.ImageViewAction | callback = com.squareup.ui.permissions.PasscodeUnlockView$4$1@338661168 (0x142f8f30) | cancelled = false | errorDrawable = null | errorResId = 0 | key = java.lang.String@316241360 (0x12d975d0) | memoryPolicy = 0 | networkPolicy = 0 | noFade = false | picasso = com.squareup.picasso.Picasso@333016576 (0x13d96e00) | request = com.squareup.picasso.Request@338645408 (0x142f51a0) | tag = com.squareup.picasso.ImageViewAction@338500224 (0x142d1a80) | target = com.squareup.picasso.Action$RequestWeakReference@338684128 (0x142fe8e0) | willReplay = false | shadow$_klass_ = com.squareup.picasso.ImageViewAction | shadow$_monitor_ = -2047389420

slide-132
SLIDE 132
slide-133
SLIDE 133
slide-134
SLIDE 134
slide-135
SLIDE 135

public interface SlackApi {
 @Multipart
 @POST("/api/files.upload")
 UploadFileResponse uploadFile( @Part("token") String token, @Part("file") TypedFile file,
 @Part("filetype") String filetype, @Part("filename") String filename,
 @Part("title") String title, @Part("initial_comment") String initialComment,
 @Part("channels") String channels );
 }


slide-136
SLIDE 136
slide-137
SLIDE 137

public class Picasso { final Map<Object, Action> targetToAction; public void cancelRequest(ImageView target) {
 Action action = targetToAction.remove(target);
 if (action != null) {
 action.cancel();
 dispatcher.dispatchCancel(action);
 }
 if (target instanceof ImageView) {…} } }

slide-138
SLIDE 138
slide-139
SLIDE 139
slide-140
SLIDE 140
slide-141
SLIDE 141

public class PasscodeUnlockView extends FrameLayout { @Override protected void onDetachedFromWindow() {
 super.onDetachedFromWindow(); picasso.cancelRequest(merchantImage);
 } }

slide-142
SLIDE 142
slide-143
SLIDE 143

public class PasscodeUnlockView extends FrameLayout { void setBackgroundImage(final RequestCreator request) {
 Views.waitForMeasure(merchantImage, new Views.OnMeasuredCallback() {
 @Override public void onMeasured(View view, int width, int height) {
 request.into(merchantImage, new Callback() {
 @Override public void onSuccess() {…}
 @Override public void onError() {…}
 });
 }
 }); } @Override protected void onDetachedFromWindow() {
 super.onDetachedFromWindow(); picasso.cancelRequest(merchantImage);
 } }

slide-144
SLIDE 144
slide-145
SLIDE 145
slide-146
SLIDE 146
slide-147
SLIDE 147
slide-148
SLIDE 148

Py ⚔ twitter.com/Piwai