Ols*_*aqe 7 android memory-leaks android-memory 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$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 ]
要重现,您需要拥有一个大的共享图像动画,还需要一个自定义的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;
}
};
Run Code Online (Sandbox Code Playgroud)
Ser*_*nko 16
泄漏的情况在于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();
}
}
Run Code Online (Sandbox Code Playgroud)
@Delargo的解决方案对我不起作用.但是,我在Android问题跟踪器上偶然发现了这个解决方案,它最终为我工作.
我们的想法是在使用活动转换的活动中使用以下类(适当命名LeakFreeSupportSharedElementCallback,从中子类SharedElementCallback化).只需将整个课程复制到您的项目中即可.
您还需要静态方法createDrawableBitmap(Drawable)以及createViewBitmap(View, Matrix, RectF)以下类.这些是由LeakFreeSupportSharedElementCallback班级使用的.
获得LeakFreeSupportSharedElementCallback类设置后,将以下内容添加到使用活动转换框架的活动中:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setEnterSharedElementCallback(new LeakFreeSupportSharedElementCallback());
setExitSharedElementCallback(new LeakFreeSupportSharedElementCallback());
}
Run Code Online (Sandbox Code Playgroud)
在过渡动画之后,GC释放了内存.
| 归档时间: |
|
| 查看次数: |
2600 次 |
| 最近记录: |