我正在使用OnGlobalLayoutListener
收听视图的布局更改:
view.getViewTreeObserver().addOnGlobalLayoutListener(myListener);
由于我对该侦听器的事件感兴趣,只要该视图存在,我认为无需调用removeOnGlobalLayoutListener(myListener)
。
这是否会导致内存泄漏,或者是否与视图一起收集了侦听器垃圾?假设侦听器持有对视图的引用。
背景是我想创建一个可以附加到某些视图的模块,并根据布局更改来完成。如果不需要删除它的创建就像new FancyModule(theView)
一样简单,然后构造函数负责绑定监听器。如果需要删除,我必须实施一个我想要阻止的析构函数方法。
答案 0 :(得分:4)
潜在的内存泄漏仅取决于您的架构。
通常情况下,不要拨打removeOnGlobalLayoutListener(myListener)
。
View
保留对ViewTreeObserver
的引用,OnGlobalLayoutListener
引用了添加的OnGlobalLayoutListener
。如果您没有对侦听器的另一个引用,则会在视图中收集垃圾。
现在,如果OnGlobalLayoutListener
的实现持有对视图的引用,那么它仍然没问题。对于Android的垃圾收集器,参考周期不是问题。
如果您有另一个包含对WeakReference
实现的引用的组件,则可以创建问题。如果组件的寿命比视图长(例如,它是通过应用程序对象保存的),那么您将通过侦听器创建视图(和上下文)的内存泄漏。
在不再使用视图时不要保持视图很重要。如何避免泄露视图的一种简单方法是使用Source Sans Pro
。
答案 1 :(得分:1)
是的,它可以泄漏。以下是LeakCanary的示例跟踪,
答案 2 :(得分:0)
我有同样的内存泄漏问题,我试图在片段的onDestroyView中注销OnGlobalLayoutListener,但是问题仍然存在,然后我尝试为视图添加onDetachListener,然后注销OnGlobalLayoutListener并成功。
在科特林我用过:
view?.doOnDetach {
onGlobalLayoutListener?.let {
view?.viewTreeObserver?.removeOnGlobalLayoutListener(it)
}
onGlobalLayoutListener = null
}
您也可以使用addOnAttachStateChangeListener方法。
答案 3 :(得分:0)
我有同样的内存泄漏问题,即使我删除了onGlobalLayoutListener
中的onDetachedFromWindow
,泄漏仍然发生:
override fun onAttachedToWindow() {
super.onAttachedToWindow()
view.viewTreeObserver.addOnGlobalLayoutListener(myListener);
}
override fun onDetachedFromWindow() {
view.viewTreeObserver.removeOnGlobalLayoutListener(myListener);
super.onDetachedFromWindow()
}
然后我在类似的问题上发现了answer:
由于您使用的是子视图的ViewTreeObserver,因此行为稍微复杂一些,一种可能的解决方案是将OnAttachStateChangeListener添加到您的scrollView并从那里添加/删除OnScrollChangedListener。
无论如何,关于泄漏的原因: getViewTreeObserver()在返回后不会返回相同的实例 视图已从窗口分离。呼唤 removeOnScrollChangedListener()可能不会起作用, 原始的OnScrollChangedListener仍附加到旧的 ViewTreeObserver,并因此泄漏您的上下文。
在OnAttachStateChangeListener
上使用view
并按照建议的方式删除监听器并没有帮助,因此,解决方案是使用活动根视图的ViewTreeObserver
:
private val activityRootView: View = (context as Activity).window.decorView.findViewById(android.R.id.content)
override fun onAttachedToWindow() {
super.onAttachedToWindow()
activityRootView.viewTreeObserver.addOnGlobalLayoutListener(myListener);
}
override fun onDetachedFromWindow() {
activityRootView.viewTreeObserver.removeOnGlobalLayoutListener(myListener);
super.onDetachedFromWindow()
}
并且不再发生泄漏。