【问题标题】:Is it possible to pass ViewModel to Fragment in a constructor?是否可以在构造函数中将 ViewModel 传递给 Fragment?
【发布时间】:2021-03-13 09:44:06
【问题描述】:

我将 Koin 用于 DI,但我试图消除对 DI 框架的依赖,所以我的问题是关于 Android 架构组件的一般性问题。

可以在片段中通过属性委托提供 ViewModel 的实例,但这会导致片段和 DI 框架之间的耦合。所以我想出了一个解决方案:在构造函数中将 ViewModel 传递给 Fragment。当前使用 Koin 的实现如下所示:

val di = module {
    fragment {
        MyFragment(
            get<MyViewModel>(),
        )
    }
    viewModel {
        MyViewModel(
            get<MyDependency>(),
        )
    }
    //...
}

而且它有效。但是有一个问题!由于 ViewModel 是在 Fragment 之前创建的,因此它不遵循 Fragment 的生命周期,并且在 Fragment 被销毁时不会调用 onCleared()

所以我想知道如何让它再次工作?

【问题讨论】:

    标签: android android-fragments android-architecture-components android-viewmodel koin


    【解决方案1】:

    实际上,这个问题根本与 Koin 无关。 要正确创建 ViewModel(绑定到生命周期),您需要引用 ViewModelProvider,可以使用 Fragment 或 Activity 创建。

    因此,您应该首先引用 Fragment 或 Activity。这使得将 ViewModel 作为构造函数参数传递给片段是不可能的。

    为了消除对 Koin 的依赖,您可以将 Koin viewModel() 扩展函数包装在自己的函数中,以便在需要时交换 DI。

    【讨论】:

    • 从我看到的 ViewModelProvider 有一个对 ViewModelStoreOwner 的引用,它是一个接口。 Activity 和 Fragment 是该接口的默认实现,但我相信 Koin 模块(或 Koin 中的范围或其他东西)可以扮演 ViewModelStoreOwner 的角色。还是我错过了将 ViewModelProvider 与活动和片段耦合的一些内容?
    • 但是如果你想将 ViewModel 绑定到活动/片段生命周期,你需要一个 ViewModelStoreOwner 作为一个生命周期所有者。否则活动结束时将没有正确的 onCleared() 调用。
    【解决方案2】:

    在基本级别,片段是一个对象,因此您可以在片段的构造函数中传递参数。但是,这不是一个好的做法,您应该始终避免这种情况,因为 android 是一个基于事件的系统,因此您必须做出相应的行为。由于这种不好的做法,可以列出许多不同的问题,但让我们关注您的问题。在内部,视图模型的 onCleared() 方法由 viewModelStoreOwner 调用,该 viewModelStoreOwner 由活动和片段实现。因此,一个活动或一个片段必须知道这个视图模型。提供这种感知的最简单方法是使用 viewModels 扩展方法。 (https://developer.android.com/kotlin/ktx#fragment)。它在内部将您的视图模型与您的片段或活动直接连接起来。然而,对于这个解决方案,我们必须考虑另一个问题,即我们如何将我们的其他对象(存储库、用例等)注入到我们的视图模型中。为此,我们需要实现自定义视图模型工厂。我不确定 Koin 是否需要这部分,所以您可以查看 https://insert-koin.io/docs/reference/koin-android/viewmodel/

    【讨论】:

    • 如果您需要更多技术解释,我可以回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-04
    • 1970-01-01
    相关资源
    最近更新 更多