Nuking nasty memory leaks - GOTO Conference · dependencies { debugCompile...

Preview:

Citation preview

Nuking nasty memory leaks

Pierre-Yves Ricau

LeakCanary

Pierre-Yves Ricau

dependencies {}A

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

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

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

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

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

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

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

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;

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

class A {}

class A {}

class B {}

class A {}

class B {}

class C {}

class A {}

class B {}

class C {}

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

class A {}

class B {}

class C {}

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

class A {}

class B {}

class C {}

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

class A {}

class B {}

class C {}

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

class A {}

class B {}

class C {}

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

class A { B b; }

class B {}

class C {}

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

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();}

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();}

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; }

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; }

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; }

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; }

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; }

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; }

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

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

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

class Activity { boolean mDestroyed = true;}

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); } }); }}

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));

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

* 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

| [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

| [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

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

}

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);

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) {…} }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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; } }

class AppCompatDelegateImplV9 {

private final Runnable mInvalidatePanelMenuRunnable = new Runnable() { @Override public void run() {…} };

private void invalidatePanelMenu(int featureId) { mWindowDecor.postOnAnimation(mInvalidatePanelMenuRunnable); } }

class AppCompatDelegateImplV9 {

private final Runnable mInvalidatePanelMenuRunnable = new Runnable() { @Override public void run() {…} };

private void invalidatePanelMenu(int featureId) { mWindowDecor.postOnAnimation(mInvalidatePanelMenuRunnable); } }

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); }

* 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

* 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

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() {…} }); } }); } }

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() {…} }); } }); } }

public class PasscodeUnlockView extends FrameLayout {

@Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); picasso.cancelRequest(merchantImage); } }

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) {…} } }

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) {…} } }

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) {…} } }

abstract class Action<T> {

boolean cancelled;

void cancel() { cancelled = true; }

}

* 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

* 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

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 ); }

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) {…} } }

public class PasscodeUnlockView extends FrameLayout {

@Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); picasso.cancelRequest(merchantImage); } }

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); } }

Py ⚔ twitter.com/Piwai

Recommended