【问题标题】:Setting up LiveData observer in custom view without LifecycleOwner在没有 LifecycleOwner 的自定义视图中设置 LiveData 观察者
【发布时间】:2018-09-14 15:55:36
【问题描述】:

我正在尝试新的 Android 架构组件,但在尝试将 MVVM 模型用于自定义视图时遇到了障碍。

基本上我已经创建了一个自定义视图来封装一个通用 UI,它是在整个应用程序中使用的相应逻辑。我可以在自定义视图中设置 ViewModel,但我必须使用 observeForever() 或在自定义视图中手动设置 LifecycleOwner,如下所示,但看起来都不正确。

选项 1) 使用 observeForever()

活动

class MyActivity : AppCompatActivity() {

    lateinit var myCustomView : CustomView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        myCustomView = findViewById(R.id.custom_view)
        myCustomView.onAttach()
    }

    override fun onStop() {
        myCustomView.onDetach()
    }
}

自定义视图

class (context: Context, attrs: AttributeSet) : RelativeLayout(context,attrs){

    private val viewModel = CustomViewModel()

    fun onAttach() {
        viewModel.state.observeForever{ myObserver }
    }

    fun onDetach() {
        viewModel.state.removeObserver{ myObserver }
    }
}

选项2)从Activity设置lifecycleOwner`

活动

class MyActivity : AppCompatActivity() {

    lateinit var myCustomView : CustomView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        myCustomView = findViewById(R.id.custom_view)
        myCustomView.setLifeCycleOwner(this)
    }
}

自定义视图

class (context: Context, attrs: AttributeSet) : RelativeLayout(context,attrs){

    private val viewModel = CustomViewModel()

    fun setLifecycleOwner(lifecycleOwner: LifecycleOwner) {
        viewModel.state.observe(lifecycleOwner)
    }
}

我只是在滥用模式和组件吗?我觉得应该有一种更简洁的方式来组合来自多个子视图的复杂视图,而不会将它们绑定到 Activity/Fragment

【问题讨论】:

  • 为什么不使用observeForever(observer) 来代替?它不需要 LifeCycleOwner 并且您可以删除 onDetachedFromWindow() 中的 Observer

标签: android mvvm android-architecture-components android-livedata android-viewmodel


【解决方案1】:

1 个选项 - 出于好意,您仍然需要做一些手动工作 - 例如,调用 onAttach\ onDetach 架构组件的主要目的是防止这样做。

2 选项 - 在我看来更好,但我会说将你的逻辑绑定在ViewModelView 周围有点错误。我相信您可以在 Activity/Fragment 内部执行相同的逻辑,而无需将 ViewModel 和 LifecycleOwner 传递给 CustomView。单个方法updateData 就足够了。

因此,在这种特殊情况下,我会说这是对架构组件的过度使用。

【讨论】:

  • 对于像我这样使用自定义视图而不是片段的人来说,这是一个问题。我将选择选项 1,因为我无法回到 Fragments 及其 LOL 生命周期。
【解决方案2】:

当我们在创建视图时已经提供了上下文时,通过将活动的一些引用传递给视图并调用 onAttach/onDetach 来手动管理视图的生命周期是没有意义的。

我在 NavigationView 中有一个片段,在视图分页器中有其他片段,更像是嵌套片段层次结构。

我在这些顶级Fragment中有一些自定义视图,当自定义视图直接在顶级Fragment中时,可以得到这样的观察者

viewModel.itemLiveData.observe((context as ContextWrapper).baseContext as LifecycleOwner,
   binding.item.text = "some text from view model"         
}

当我将自定义视图作为活动的直接子项时,我将其直接设置为

viewModel.itemLiveData.observe(context as LifecycleOwner,
   binding.item.text = "some text from view model"         
}

在这些活动中,如果我有一个片段并且它有一些自定义视图并且我使用第二种方法,我会得到一个 ClassCastException(),我必须在不同的地方重用这些自定义视图,包括活动和片段(这就是拥有自定义视图的想法)

所以我写了一个扩展函数来设置 LifeCycleOwner

fun Context.getLifecycleOwner(): LifecycleOwner {
    return try {
        this as LifecycleOwner
    } catch (exception: ClassCastException) {
        (this as ContextWrapper).baseContext as LifecycleOwner
    }
}

现在我只是把它设置为

viewModel.itemLiveData.observe(context.getLifecycleOwner(),
   binding.item.text = "some text from view model"         
}

【讨论】:

  • 一个片段可以有两个生命周期所有者:片段本身或片段视图 (viewLifecycleOwner)。在我们的例子中,如果自定义视图在片段中被夸大,我们需要以某种方式获取viewLifecycleOwner
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多