SharedElement and user EnterTransition cause memory leak

The presence of animation of a common element, as well as custom input animation, leads to a leak of activity.

Any idea what could be causing?

09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * com.feeln.android.activity.MovieDetailActivity has leaked: 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * GC ROOT android.app.ActivityThread$ApplicationThread.this$0 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.app.ActivityThread.mActivities 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.util.ArrayMap.mArray 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references array java.lang.Object[].[1] 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.app.ActivityThread$ActivityClientRecord.activity 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references com.feeln.android.activity.MovieDetailActivity.mActivityTransitionState 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.app.ActivityTransitionState.mEnterTransitionCoordinator 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.app.EnterTransitionCoordinator.mEnterViewsTransition 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.transition.TransitionSet.mParent 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.transition.TransitionSet.mListeners 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references java.util.ArrayList.array 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references array java.lang.Object[].[1] 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.transition.TransitionManager$MultiListener$1.val$runningTransitions (anonymous class extends android.transition.Transition$TransitionListenerAdapter) 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.util.ArrayMap.mArray 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references array java.lang.Object[].[2] 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references com.android.internal.policy.impl.PhoneWindow$DecorView.mContext 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * leaks com.feeln.android.activity.MovieDetailActivity instance 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ [ 09-21 16:19:31.007 28269:31066 D/LeakCanary ] * Reference Key: af2b6234-297e-4bab-96e9-02f1c4bca171 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * Device: LGE google Nexus 5 hammerhead 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * Android Version: 5.1.1 API: 22 LeakCanary: 1.3.1 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * Durations: watch=6785ms, gc=262ms, heap dump=8553ms, analysis=33741ms 09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ [ 09-21 16:19:31.007 28269:31066 D/LeakCanary ]

To play, you need to have a large general animation of the images, as well as the user-defined function EnterAnimation and setEnterSharedElementCallback. All this from the support library.

This is how I installed EnterTransition:

 private SharedElementCallback mCallback = new SharedElementCallback() { @Override public void onSharedElementStart(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if(sharedElements.size()>0) getWindow().setEnterTransition(makeEnterTransition(getWindow().getEnterTransition(), getSharedElement(sharedElements))); } } private View getSharedElement(List<View> sharedElements) { for (final View view : sharedElements) { if (view instanceof ImageView) { return view; } } return null; } }; 
+7
android memory-leaks android-memory leakcanary
source share
2 answers

The case of leaks lies in TransitionManager.sRunningTransitions , where each DecorView adds and never removes. DecorView has a link to its Activity Context . Because sRunningTransitions is a static field, it has a constant chain of links to Activity that will never be compiled by the GC.

I don’t know why TransitionManager.sRunningTransitions is needed, but if you remove Activity DecorView from it, your problem will be solved. Follow the code example for how to do this. In your activity class:

 @Override protected void onDestroy() { super.onDestroy(); removeActivityFromTransitionManager(Activity activity); } private static void removeActivityFromTransitionManager(Activity activity) { if (Build.VERSION.SDK_INT < 21) { return; } Class transitionManagerClass = TransitionManager.class; try { Field runningTransitionsField = transitionManagerClass.getDeclaredField("sRunningTransitions"); runningTransitionsField.setAccessible(true); //noinspection unchecked ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>> runningTransitions = (ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>) runningTransitionsField.get(transitionManagerClass); if (runningTransitions.get() == null || runningTransitions.get().get() == null) { return; } ArrayMap map = runningTransitions.get().get(); View decorView = activity.getWindow().getDecorView(); if (map.containsKey(decorView)) { map.remove(decorView); } } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } 
+11
source share

@Delargo's solution did not help me. However, I came across this solution on an Android tracker that finally worked for me.

The idea is to use the following class (aptly named LeakFreeSupportSharedElementCallback , a subclass of SharedElementCallback ) in actions that use activity transitions. Just copy the whole class into your project.

You will also need the static methods createDrawableBitmap(Drawable) and createViewBitmap(View, Matrix, RectF) from the following class. They are used by the LeakFreeSupportSharedElementCallback class.

  1. TransitionUtils

After you have set up the LeakFreeSupportSharedElementCallback class LeakFreeSupportSharedElementCallback , add the following actions to the actions that use the transition infrastructure:

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { setEnterSharedElementCallback(new LeakFreeSupportSharedElementCallback()); setExitSharedElementCallback(new LeakFreeSupportSharedElementCallback()); } 

With the fact that the memory was freed by the GC after the transition animation.

+5
source share

All Articles