【问题标题】:Using view model to pass data between fragments使用视图模型在片段之间传递数据
【发布时间】:2021-12-31 00:05:42
【问题描述】:

我是 Android 开发和制作 Android 地图应用的新手。现在,我有三个片段:一个是地图,两个是位置的回收站视图列表。在我的主要活动中,它们都在导航主机中。我想要做的是单击列表中的位置,它会将我带到地图片段并在地图上放置一个标记。

我的想法是在我的列表片段中设置视图模型,并在我的地图片段中获取视图模型。

我的视图模型:

private val _location = MutableLiveData<Location>()
val location: LiveData<Location> = _location

fun setLocation(location: Location) {
    _location.value = location
}

我在位置片段中的点击监听器:

private var clickListenerImpl = object : LocationsAdapter.OnClickListener {
    override fun onNameClick(location: Location) {
        viewModel.setLocation(location)
        view?.findNavController()?.navigate(
            LocationsFragmentDirections.actionLocationsToMap()
        )
    }
}

我的地图就绪回调:

viewModel.location.observe(viewLifecycleOwner, { location ->
    googleMap.addMarker(
        MarkerOptions()
            .position(LatLng(location.lat, location.lng))
    )
})

我使用的视图模型对吗?我无法在地图片段中获取我的视图模型数据,也无法在我的其他列表片段中获取。我尝试在位置和地图片段中使用日志。似乎它在位置片段中正确设置了视图模型,但地图片段仍然认为它是空的,所以它不会更新。或者有没有更好的方法来代替使用视图模型?


谢谢大家。我真的很想给大家点赞,但我的名声太低了,不能这样做。

虽然我真的很想使用 ViewModel,但我仍然无法让它在活动范围内工作。也许当我在一个新片段中启动它时,它会覆盖它的旧值?我不知道。

private val viewModel: LocationViewModel by activityViewModels {
    LocationViewModelFactory((requireActivity().application as LocationApplication).repository)
}

我的解决方案已更改为使用 SafeArgs。将纬度和经度转换为浮点类型需要额外的步骤,但可以完成工作。

【问题讨论】:

    标签: android kotlin


    【解决方案1】:

    您使用的是活动范围的 ViewModel 吗?您需要使用活动范围的 ViewModel 或导航范围的 viewModel 才能工作。如果您在地图中使用片段范围的 ViewModel 并列出片段。该片段将获得您的 ViewModel 的不同实例。 在我看来,我只是将位置数据作为片段参数传递,而不是共享 ViewModel。

    【讨论】:

    • 谢谢,我明白了。我可能没有使用活动范围的 ViewModel。您说将数据作为片段参数传递是指使用 SafeArgs 还是捆绑包?
    • SafeArgs 您是否已经在使用导航组件。
    【解决方案2】:

    ViewModel 的工作方式如下:

    1. 每个ViewModel 都(应该)绑定到一个LifeCycleOwner,它指的是FragmentActivity。换句话说,每个ViewModel 都绑定到一个FragmentActivity

    2. 为了在Fragments之间共享(ViewModel's)数据,使用SharedViewModel模式,想法是,这个ViewModel将绑定到外部(父)Activity,对于它的每个子 Fragment,您可以使用以下方法获取此 ViewModel 实例:

       ViewModelProvider(requireActivity()).get(MainViewModel::class.java) 
      

    【讨论】:

    • 嗨,因为我也在使用 Room。我关注了这个 Codelab:developer.android.com/codelabs/…。所以我的 ViewModel 绑定到一个像这样的应用程序 private val wordViewModel: WordViewModel by viewModels { WordViewModelFactory((application as WordsApplication).repository) } 这是我无法获取实例的原因吗?
    • @tdyin 这可能会有所帮助:stackoverflow.com/questions/65352324/…
    • 哦,我明白了。他们是一样的。谢谢。
    【解决方案3】:

    想到了两种实现片段之间共享 ViewModel 数据的方法。

    1. 使用activityViewModels()。只要父 Activity 处于活动状态,这将使 ViewModel 保持活动状态。见Share Data Between Fragments Using ViewModels

    private val model: SharedViewModel by activityViewModels()

    编辑:activityViewModels 与 ViewModelFactory 一起使用

    private val model: SharedViewModel by activityViewModels() {
       ExampleViewModelFactory(
         repository
       )
    }
    
    1. 第二种方法是在 Activity 中实例化一个 ViewModel,然后在每个 Fragment 中抓取要使用的对象。几乎就像一个单身人士。

    【讨论】:

    • 嗨,我看这篇文章。我不能使用它,因为我也在使用 Room。所以我必须通过使用 ViewModel Factory 和我的存储库类的参数来启动 ViewModel。但我认为你的第二种方式是个好主意。让我试试看。
    • 我更新了答案,举了一个使用带有 ViewModel 工厂的`activityViewModels()` 的示例。只需将存储库类的相同实例传递给工厂。您可以再次使用在 Activity 中实例化存储库类的想法,使用 Singleton,和/或如果您真的想获得高级的 DI 框架,如 Dagger。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-07
    • 1970-01-01
    • 2016-11-21
    • 1970-01-01
    • 2017-03-08
    • 1970-01-01
    相关资源
    最近更新 更多