android-fragments - 如何通过 Dagger2.2 注入(inject)的不同存储库实现重用 Fragment 和 ViewModel

标签 android-fragments dagger-2 dagger android-viewmodel android-mvvm

我对 Android 开发有点陌生,一直在寻找一种使用 Dagger2、Fragments 和 ViewModel 等 Android 库来实现此模式的方法。

我希望你们中的一些人可以帮助我解决这个问题,或者说明在 Android 上执行此操作的常见方法是什么。

我正在寻找这样的东西:

class FragmentPager: Fragment() {

@Inject
@Named("FullListFragment")
lateinit var listFragment: ListFragment

@Inject
@Named("FilteredListFragment")
lateinit var filteredListFragment: ListFragment

//Use fragments in the viewPager. 

}

我想做的事情:

我有一个显示元素列表的片段。它还有一个 ViewModel 负责更新列表等。 ViewModel 从查询数据库的存储库获取列表。到目前为止非常简单。

我的用例是我的应用程序显示应用程序内许多不同区域但具有不同数据的元素列表。例如完整列表、过滤列表...

我的想法是将存储库创建为具有单一方法的接口(interface):fun getItems(): List<Item>以及每个数据源的不同实例。结果,我有:

  • ListFragment(继承自Fragment的类)
  • ListViewModel(继承自 ViewModel 的类)
  • ListRepository(接口(interface))
  • FullListRepository(实现 ListRepository 的类)--> 从数据库获取所有项目
  • FilterListRepository(实现ListRepository的类)-->从数据库获取过滤项
  • JoinedListRepository(实现 ListRepository 的类)--> 从数据库获取项目,但通过连接不同的表

这些元素将在这样的理想世界中协同工作:

fun buildListFragment(repository: ListRepository) {
    val viewModel = ListViewModel(repository)
    val fragment = ListFragment(viewModel)
    return fragment
}

val fullListFragment = buildListFragment(FullListRepository())
val filteredListFragment = buildListFragment(FilterListRepository())
val joinedListFragment = buildListFragment(JoinedListRepository())

如何使用 Dagger2 注入(inject)依赖项、使用 ViewModelFactory 创建 ViewModel 和 Fragments 来执行类似的操作。

我遇到的限制:

  • 我的 ViewModel 有参数,因此只能通过 ViewModelFactory 创建。
  • ViewModel 无法通过构造函数注入(inject)到 Fragment 中,需要在 onCreate 中使用 viewModelFactory 在内部创建。此时不可能告诉 Dagger2 应使用哪个 ListRepository 实现来创建 ViewModelFactory。
class ListFragment: Fragment() {
   @Inject
   lateinit var viewModelFactory: ViewModelProvider.Factory

   override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {

        viewModel = ViewModelProvider(this, viewModelFactory).get(CardListViewModel::class.java)
    }

}
  • 我知道您可以使用 @Named 注释来请求注入(inject)不同的存储库实现,但是当在 Fragment 主体内创建工厂时,请求 @Named 存储库为时已晚,因为您之前知道需要哪个存储库不在之后创建片段。

问题:

  • 使用 Dagger2 和 ViewModel 可以实现此解决方案吗?
  • 我怎样才能实现它?有什么建议吗?
  • 您通常会使用适契约(Contract)一用例的其他模式吗?

最佳答案

我通常会在发布答案之前测试我的答案,但与 Mr. Dagger 那就太多了。也就是说,这是我有根据的猜测:

拥有知道如何提取 3 个不同数据集(完整数据集、过滤数据集、连接数据集)的单个片段意味着它需要以某种方式进行参数化。我想这可以通过命名注入(inject)来完成,但我只需在需要时使用 MyFragment.newInstanceA()MyFragment.newInstanceB() 等即可。

在片段内部,可能使用 android 注入(inject),就像我认为你已经在做的那样,单个自由形式工厂是构造函数注入(inject)的,所有 3 个存储库实现了单个接口(interface)。该工厂将包装您的 ViewModelProvider.Factory 实现,并具有一个方法(例如 create),其中带有实例化片段的参数。

根据参数值,工厂将创建并返回 ViewModelProvider.Factory 的正确参数化实现。然后, View 模型提供程序将能够获取正确参数化的 View 模型。我知道这不是很多 Dagger ,但理论上它应该可以工作:)

PS:如果数据本质上显然来自单个存储,我不会创建 3 个不同的存储库。可能需要在 View 模型下完成不同存储库方法的调用。

关于android-fragments - 如何通过 Dagger2.2 注入(inject)的不同存储库实现重用 Fragment 和 ViewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60335981/

相关文章:

android - Activity 中的 OnOptionsItemSelected 在 fragment 中的 onOptionsItemSelected 之前被调用。其他方式可能吗?

java - 如何使用 dagger 2 才能使用共享首选项的抽象表示?

android - android.content.Context.getString 中的 NPE 导致应用程序在启动时崩溃

java - Dagger 2,MVVM : Adding a third tab and going back and forth crashes the app

android - 有没有办法在 TabHost 中显示 fragment ?

java - 对于选项卡式 Activity 中使用 fragment 的 GridView ,适配器为空

android - Dagger2 - 生成的组件类中的 "Unused"模块

java - 我的 ViewModel 无法在配置更改后继续存在

android - [ Dagger 1.x] : Specifying the ObjectGraph itself as a dependency for a class?

android - 忽略导航()调用