【发布时间】:2021-07-28 16:59:47
【问题描述】:
问题:我面临片段和共享的问题 viewmodel LiveData ...问题是存在 FragmentA更新共享 viewmodel 中的数据并观察其变化,然后在 FragmentA 中为用户显示结果,FragmentA 可以启动 的新实例>FragmentA 获取新数据并显示它,以便片段自行启动并将旧实例添加到后台堆栈,直到这里没有任何问题,新实例更新 LiveData 中的 viewModel 并完美显示新数据问题是当我 popUpBackstack() 返回到 FragmentA 旧实例时,其中显示的数据是新的数据FragmentA 实例得到它,这意味着即使我移除了观察者,旧的 FragmentA 实例仍在观察数据......这是一般情况关于问题的概述,现在我将向您展示片段结构、代码以及我尝试过的解决方案。
预期行为:我想要实现的是,当 FragmentA 自行启动并添加到后端堆栈时,停止观察 viewModel 中的数据,当我返回它时仅显示旧数据。
- 片段结构:我使用一个活动来保存所有片段... MainActivity 里面有 FindMoviesFragment 里面有一个 viewPager FragmentMovies 启动 MovieDetailsFragment 并在其中有 ViewPager 还保存显示来自 MoviesViewModel 的数据的片段看到下面的代码就明白了。
这段代码展示了MovieDetailsFragment如何初始化MoviesViewModel并更新viewmodel中的数据:
class MovieDetailsFragment:Fragment(R.layout.movie_details_fragment) {
private val args: MovieDetailsFragmentArgs by navArgs()
private val fragmentList:ArrayList<Fragment> by lazy {
arrayListOf(MovieDetailsOneFragment(args.movieId), MovieDetailsTwoFragment(),MovieDetailsThreeFragment())
}
private lateinit var pagerAdapter: ViewPagerAdapter
private lateinit var moviesViewModel: MoviesViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
moviesViewModel = ViewModelProvider(requireActivity()).get(MoviesViewModel::class.java)
//these two lines updates the data in viewmodel
moviesViewModel.getMovieDetails(args.movieId)
moviesViewModel.changeMovieID(args.movieId)
}
}
//---------------------MoviesViewModel------------------//
class MoviesViewModel constructor(private val repo:Repository):ViewModel() {
private val _currentMovieDetails = MutableLiveData<Resource<MovieDetails>>()
val currentMovieDetails :LiveData<Resource<MovieDetails>>
get() = _currentMovieDetails
fun getMovieDetails(movieID:Int) = viewModelScope.launch {
_currentMovieDetails.postValue(Resource.loading(null))
val result = repo.getMovieDetails(movieID)
if(result.isSuccessful){
_currentMovieDetails.postValue(Resource.success(result.body()))
}
else{
_currentMovieDetails.postValue(Resource.error(result.errorBody().toString(),null))
}
}
}
在 MovieDetailsFragment 的 viewpager 内的 MovieDetailsOne 中,我观察到这样的数据:
class MovieDetailsOneFragment(private val movieId: Int):Fragment(R.layout.movie_details_one) {
private lateinit var moviesViewModel:MoviesViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//this is how i define viewModel(global scope)
moviesViewModel = ViewModelProvider(requireActivity()).get(MoviesViewModel::class.java)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//in this method i observe on changes in currentMovieDetils liveData
subscribeToObservers()
//i try to call this from on create and nothing changes too
}
}
现在我尝试的是以下内容:
-片段的本地范围
//Define viewModel like this in MovieDetilsFragment
moviesViewModel = ViewModelProvider(this).get(MoviesViewModel::class.java)
//And in MovieDetailsOne like this
moviesViewModel = ViewModelProvider(this).get(MoviesViewModel::class.java)
//and this doesn't work MovieDetailsOne don't observe any changes
-观察一次消光函数:
fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observer<T>) {
observe(lifecycleOwner, object : Observer<T> {
override fun onChanged(t: T?) {
observer.onChanged(t)
removeObserver(this)
}
})
}
//and this doesn't work MovieDetailsOne don't observe first time it's lanches
我知道我花了很长时间来解释:D,但我试图给你一个清晰的想法,对不起你的时间
【问题讨论】:
标签: android kotlin fragment android-livedata android-viewmodel