gpt4 book ai didi

android - Kotlin 委托(delegate)破坏导航

转载 作者:行者123 更新时间:2023-12-03 20:02:34 29 4
gpt4 key购买 nike

我正在尝试 Jetpack Navigation component并设置了一个非常基本的导航图,其中只有 2 个 fragment ,其中一个主 fragment (Foo) 包含一个按钮,该按钮调用导航操作以打开另一个 fragment (Bar)。
仅使用基本的 Android 用法和按预期工作的功能,我可以导航回 Foo按返回按钮并向前导航到 Bar再次。
我实现了这种便利delegate以我喜欢的方式按 id 绑定(bind) View 的类(我最初是 iOS 开发人员)。

class FindViewById<in R, T: View>(private val id: Int) {

private var view: T? = null

operator fun getValue(thisRef: R, property: KProperty<*>): T {
var view = this.view
if (view == null) {
view = when (thisRef) {
is Activity -> thisRef.findViewById(id)!!
is Fragment -> thisRef.requireView().findViewById(id)!!
is View -> thisRef.findViewById(id)!!
else -> throw NullPointerException()
}
this.view = view // Comment out to never cache reference
}
return view
}
}
这使我可以编写这样的代码
class FragmentFoo: Fragment() {

private val textView: TextView by FindViewById(R.id.text_view)
private val button: Button by FindViewById(R.id.button)
...

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

button.setOnClickListener {
findNavController().navigate(R.id.action_foo_to_bar)
}
}
}

现在突然间当我导航到 Bar然后按返回按钮我到达 Foo再次,但我无法前进到 Bar .如果我删除行 this.view = viewFindViewById它再次起作用。
我的猜测是存在一些与内存相关的问题,尽管我尝试包装 viewWeakReference 内但它并没有解决问题。
我认为在委托(delegate)中缓存找到的 View 在性能方面是一个好主意。
知道为什么会发生这种情况以及如何在缓存找到的 View 时解决问题吗?
编辑
我的 Intent 不是找到另一种引用 View 的方式,而是为什么这个委托(delegate)实现会破坏导航组件,所以如果我将来要制作另一个自定义委托(delegate),我就不会再体验它了。
解决方案
is Fragment -> {
thisRef.viewLifecycleOwnerLiveData.value!!.lifecycle.addObserver(object: LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
if (event == Lifecycle.Event.ON_STOP) this@FindViewById.view = null
}
})
return thisRef.requireView().findViewById(id)!!
}

最佳答案

在安卓 Fragment View 有自己定义明确的lifecycle并且这个生命周期独立于 fragment 的生命周期进行管理。
当您使用导航组件时,它使用 fragment replace transaction在引擎盖下并将前一个 fragment 添加到后堆栈。此时此 fragment 进入 CREATED状态,正如您在 diagram 上看到的那样它的 View 实际上被破坏了。此时,您的委托(delegate)仍然保留对这个旧 View 层次结构的引用,从而导致内存泄漏。
稍后,当您导航返回时, fragment 会返回 STARTED进入 RESUMED状态,但是 重新创建 View 层次结构 - onCreateViewonViewCreated在此过程中再次调用方法。因此,当 fragment 显示一个全新的 View 层次结构时,您的委托(delegate)仍然引用旧的。
因此,如果您想手动缓存任何 View 引用,则需要覆盖 onDestroyView并清除这些引用以避免内存泄漏和这种不正确的行为。对于这个特殊问题,我建议使用 ViewBinding .
如果您想拥有自己的实现,但不想清除 onDestroyView 中的引用(例如,因为它破坏了良好且独立的抽象),viewLifecycleOwnerLiveData可能有助于观察当前 View 状态并在 View 被销毁时清除所有引用。
请查看 fragments文档,它最近已更新并涵盖了 fragment 的大部分方面。

关于android - Kotlin 委托(delegate)破坏导航,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65004918/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com