使用 jetpack 导航时,RecyclerView 会导致内存泄漏吗?
will RecyclerView cause a memory leak while working with jetpack navigation?
假设我有这样一个片段
class MyFragment : Fragment() {
// Suppose there is a binding, which contains a recyclerView
private var _binding: FragmentAbinding? = null
val binding get() = _binding!!
// Suppose there is a recyclerView adapter
val adapter by lazy { MyAdapter() }
// use navigation as router
private val navController: NavController by lazy { findNavController() }
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentAbinding.inflate(
inflater,
container,
false
)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// ...
binding.recyclerView.adapter = adapter
// ...
}
override fun onDestroyView() {
_binding = null
}
}
当使用navController.navigate(...)时,MyFragment会被替换,并且_binding 将为空。然而,由于recyclerView使用观察者模式观察适配器中的数据集,因此适配器将持有recyclerView作为其观察者。导航到另一个fragment后(即onDestroyView()后),recyclerView会不会主动取消对adapter数据集的观察,也就是说adapter不会持有recyclerView的实例?
我使用下面的方法删除适配器数据集观察者
fun RecyclerView.Adapter<*>.removeObservers() {
var clazz: Class<*> = javaClass
val simpleName = RecyclerView.Adapter::class.simpleName
while (clazz.simpleName != simpleName) {
clazz = clazz.superclass
}
val field = clazz.getDeclaredField("mObservable")
field.isAccessible = true
val observable = field[this] as Observable<*>
observable.unregisterAll()
}
// in fragment
class MyFragment : Fragment() {
override fun onDestroyView() {
adapter.removeObservers()
}
}
适配器在调用“onCreateViewHolder”时使用 recyclerView 作为视图组,当您使用导航进行导航时,您的片段只是视图被销毁但它的实例仍然存在于后台堆栈中,您的适配器也是如此,因为那是一个 class-level 解决这个问题的变量你应该在视图生命周期事件(onViewCreated.. onDestroyView)中创建适配器。
假设我有这样一个片段
class MyFragment : Fragment() {
// Suppose there is a binding, which contains a recyclerView
private var _binding: FragmentAbinding? = null
val binding get() = _binding!!
// Suppose there is a recyclerView adapter
val adapter by lazy { MyAdapter() }
// use navigation as router
private val navController: NavController by lazy { findNavController() }
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentAbinding.inflate(
inflater,
container,
false
)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// ...
binding.recyclerView.adapter = adapter
// ...
}
override fun onDestroyView() {
_binding = null
}
}
当使用navController.navigate(...)时,MyFragment会被替换,并且_binding 将为空。然而,由于recyclerView使用观察者模式观察适配器中的数据集,因此适配器将持有recyclerView作为其观察者。导航到另一个fragment后(即onDestroyView()后),recyclerView会不会主动取消对adapter数据集的观察,也就是说adapter不会持有recyclerView的实例?
我使用下面的方法删除适配器数据集观察者
fun RecyclerView.Adapter<*>.removeObservers() {
var clazz: Class<*> = javaClass
val simpleName = RecyclerView.Adapter::class.simpleName
while (clazz.simpleName != simpleName) {
clazz = clazz.superclass
}
val field = clazz.getDeclaredField("mObservable")
field.isAccessible = true
val observable = field[this] as Observable<*>
observable.unregisterAll()
}
// in fragment
class MyFragment : Fragment() {
override fun onDestroyView() {
adapter.removeObservers()
}
}
适配器在调用“onCreateViewHolder”时使用 recyclerView 作为视图组,当您使用导航进行导航时,您的片段只是视图被销毁但它的实例仍然存在于后台堆栈中,您的适配器也是如此,因为那是一个 class-level 解决这个问题的变量你应该在视图生命周期事件(onViewCreated.. onDestroyView)中创建适配器。