本文介绍了SharedElement和自定义EnterTransition导致内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具有共享元素动画和自定义输入动画会导致活动泄漏.

Having a shared element animation and also a custom enter animation causes the activity to leak.

任何想法可能是什么原因?

Any idea what might be the cause?

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$009-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.app.ActivityThread.mActivities09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.util.ArrayMap.mArray09-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.activity09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references com.feeln.android.activity.MovieDetailActivity.mActivityTransitionState09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.app.ActivityTransitionState.mEnterTransitionCoordinator09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.app.EnterTransitionCoordinator.mEnterViewsTransition09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.transition.TransitionSet.mParent09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.transition.TransitionSet.mListeners09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references java.util.ArrayList.array09-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.mArray09-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.mContext09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * leaks com.feeln.android.activity.MovieDetailActivity instance09-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-02f1c4bca17109-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * Device: LGE google Nexus 5 hammerhead09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * Android Version: 5.1.1 API: 22 LeakCanary: 1.3.109-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * Durations: watch=6785ms, gc=262ms, heap dump=8553ms, analysis=33741ms09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ [ 09-21 16:19:31.007 28269:31066 D/LeakCanary ]

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$009-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.app.ActivityThread.mActivities09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.util.ArrayMap.mArray09-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.activity09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references com.feeln.android.activity.MovieDetailActivity.mActivityTransitionState09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.app.ActivityTransitionState.mEnterTransitionCoordinator09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.app.EnterTransitionCoordinator.mEnterViewsTransition09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.transition.TransitionSet.mParent09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references android.transition.TransitionSet.mListeners09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * references java.util.ArrayList.array09-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.mArray09-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.mContext09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * leaks com.feeln.android.activity.MovieDetailActivity instance09-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-02f1c4bca17109-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * Device: LGE google Nexus 5 hammerhead09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * Android Version: 5.1.1 API: 22 LeakCanary: 1.3.109-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ * Durations: watch=6785ms, gc=262ms, heap dump=8553ms, analysis=33741ms09-21 16:19:31.007 28269-31066/com.sample.android D/LeakCanary﹕ [ 09-21 16:19:31.007 28269:31066 D/LeakCanary ]

要重现,您需要具有较大的共享图像动画,还需要自定义EnterAnimation和setEnterSharedElementCallback.所有这些都来自支持库.

To reproduce you need to have a big shared image animation and also a custom EnterAnimation and setEnterSharedElementCallback . All this are from the support library.

这是我设置EnterTransition的方式:

Here is how i set the 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;
    }
};

推荐答案

泄漏的原因在于TransitionManager.sRunningTransitions,每个DecorView都会添加而不会删除. DecorView链接到他的ActivityContext.由于sRunningTransitions是静态字段,因此它具有对Activity的永久引用链,GC永远不会收集它.

Case of leaks lies in TransitionManager.sRunningTransitions where each DecorView adds and never removes. DecorView has link to his Activity's Context. Because of sRunningTransitions is static field, it has permanent chain of references to Activity, which will never be collected by GC.

我不知道为什么需要TransitionManager.sRunningTransitions,但是如果从其中删除ActivityDecorView,您的问题将得到解决.遵循代码为例,该怎么做.在您的活动课程中:

I don't known why TransitionManager.sRunningTransitions needs, but if you remove Activity's DecorView from it, your problem will be solved. Follow code is example, how do it. 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();
    }
}

这篇关于SharedElement和自定义EnterTransition导致内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-27 13:23