android – SharedElement和自定义EnterTransition导致内存泄漏

前端之家收集整理的这篇文章主要介绍了android – SharedElement和自定义EnterTransition导致内存泄漏前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
拥有共享元素动画以及自定义输入动画会导致活动泄漏.

知道可能是什么原因?

09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:* com.feeln.android.activity.MovieDetailActivity已泄露:
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:*引用android.app.ActivityThread.mActivities
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*引用android.util.ArrayMap.mArray
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*引用数组java.lang.Object [].[1]
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*引用android.app.ActivityThread $ActivityClientRecord.activity
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*引用com.feeln.android.activity.MovieDetailActivity.mActivityTransitionState
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*引用android.app.ActivityTransitionState.mEnterTransitionCoordinator
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*引用android.app.EnterTransitionCoordinator.mEnterViewsTransition
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*引用android.transition.TransitionSet.mParent
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*引用android.transition.TransitionSet.mListeners
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*引用java.util.ArrayList.array
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*引用数组java.lang.Object [].[1]
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*引用android.transition.TransitionManager $MultiListener $1.val $runningTransitions(匿名类扩展android.transition.Transition $TransitionListenerAdapter)
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*引用android.util.ArrayMap.mArray
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*引用数组java.lang.Object [].[2]
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*引用com.android.internal.policy.impl.PhoneWindow $DecorView.mContext
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*泄漏com.feeln.android.activity.MovieDetailActivity实例
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:[09-21 16:19:31.007 28269:31066 D / LeakCanary]
*参考密钥:af2b6234-297e-4bab-96e9-02f1c4bca171
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*设备:LGE google Nexus 5 hammerhead
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:* Android版本:5.1.1 API:22 LeakCanary:1.3.1
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:*持续时间:watch = 6785ms,gc = 262ms,堆转储= 8553ms,分析= 33741ms
09-21 16:19:31.007 28269-31066 / com.sample.android D / LeakCanary:[09-21 16:19:31.007 28269:31066 D / LeakCanary]

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

以下是我设置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链接到他的Activity的Context.由于sRunningTransitions是静态字段,因此它具有对Activity的永久链引用,GC永远不会收集它.

我不知道为什么需要TransitionManager.sRunningTransitions,但是如果从中移除Activity的DecorView,你的问题就会得到解决.按照代码示例,怎么做.在您的活动类中:

@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();
    }
}
原文链接:https://www.f2er.com/android/316604.html

猜你在找的Android相关文章