我有一个包含片段的活动。运行Leak Canary,我发现该活动存在内存泄漏。我已注释掉所有从活动和片段到活动仅显示片段且片段具有空xml布局的代码。我在文件或xml中都无法访问。
答案 0 :(得分:2)
好的,我实际上已经知道了。这是Snackbar中的内存泄漏,下面是如何复制它的方法:https://github.com/GC-Xi/SnackbarBug
再现方式
原因
SnackbarBaseLayout
在构造函数中调用addTouchExplorationStateChangeListener()
,在removeTouchExplorationStateChangeListener()
中调用onDetachedFromWindow()
。可能应该从addTouchExplorationStateChangeListener()
调用onAttachedToWindow()
的地方,因为除非调用SnackbarBaseLayout
,否则Snackbar.show()
不会附加到窗口。
解决方案1
更新到AndroidX,并改用com.google.android.material.snackbar.Snackbar。 https://github.com/GC-Xi/SnackbarBug/tree/solution1
解决方案2
除非准备好显示它,否则请不要创建它。 https://github.com/GC-Xi/SnackbarBug/tree/solution2
答案 1 :(得分:1)
我遇到了类似的问题。我当时持有对Snackbar的引用。我删除该引用后,此内存泄漏消失了。
更新
例如,替换
val snackbar = Snackbar.make(rootLayout, "Hello Snackbar", Snackbar.LENGTH_INDEFINITE)
snackbar.show()
使用
Snackbar.make(rootLayout, "Hello Snackbar", Snackbar.LENGTH_INDEFINITE).show()
我不知道为什么它可以解决我的问题。我无法在其他项目中重现此内存泄漏。基于堆栈跟踪,似乎BaseTransientBottomBar.onDetachedFromWindow()
没有被系统调用,因此touchExplorationStateChangeListener
并未从accessibilityManager
中删除。同样,我不知道为什么会这样。以下是BaseTransientBottomBar.onDetachedFromWindow()
的代码。
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (this.onAttachStateChangeListener != null) {
this.onAttachStateChangeListener.onViewDetachedFromWindow(this);
}
AccessibilityManagerCompat.removeTouchExplorationStateChangeListener(this.accessibilityManager, this.touchExplorationStateChangeListener);
}