Android 带有viewmodel和live数据的ViewPager,所有6个选项卡数据都将替换为最后一个选项卡数据
我正在使用一个带有6个选项卡的Android 带有viewmodel和live数据的ViewPager,所有6个选项卡数据都将替换为最后一个选项卡数据,android,android-viewpager,android-livedata,android-viewmodel,Android,Android Viewpager,Android Livedata,Android Viewmodel,我正在使用一个带有6个选项卡的查看页面,其中只有一个片段TimesListFragment 根据传递给TimesListFragment的参数,它调用api eg;科学、技术、旅游等 我的应用程序遵循了谷歌的GithubBrowserSample 我有TimesListFragment->TimesViewModel->TimesRepository 有6个选项卡,当我点击api时,所有选项卡都显示相同的结果,如果是最后一个参数 StoriesPagerAdapter.kt class Stor
查看页面
,其中只有一个片段TimesListFragment
根据传递给TimesListFragment
的参数,它调用api eg;科学、技术、旅游等
我的应用程序遵循了谷歌的GithubBrowserSample
我有TimesListFragment
->TimesViewModel
->TimesRepository
有6个选项卡,当我点击api时,所有选项卡都显示相同的结果,如果是最后一个参数
StoriesPagerAdapter.kt
class StoriesPagerAdapter(fragmentManager: FragmentManager?)
:FragmentStatePagerAdapter(fragmentManager){
private val sections= arrayListOf("science","technology","business","world","movies","travel")
override fun getItem(position: Int): Fragment {
return TimesListFragment.newInstance(sections[position])
}
override fun getCount(): Int {
return sections.size
}
override fun getPageTitle(position: Int): CharSequence? {
return sections[position]
}
}
class TimesRepository @Inject constructor(private val apiService: ApiService,
private val timesDao: TimesDao,
private val appExecutors: AppExecutors) {
private val repoListRateLimit = RateLimiter<String>(10, TimeUnit.MINUTES)
fun loadStories(section:String): LiveData<Resource<TimesStoriesResponse>> {
return object : NetworkBoundResource<TimesStoriesResponse, TimesStoriesResponse>(appExecutors) {
override fun saveCallResult(item: TimesStoriesResponse) {
timesDao.insert(item)
}
override fun shouldFetch(data: TimesStoriesResponse?): Boolean {
return data == null || repoListRateLimit.shouldFetch(section)
}
override fun loadFromDb() = timesDao.load()
override fun createCall() = apiService.getTopStories(section,ConfigConstant.TIMES_KEY)
override fun onFetchFailed() {
repoListRateLimit.reset(section)
}
}.asLiveData()
}
interface ApiService {
@GET("svc/topstories/v2/{section}.json?")
fun getTopStories(@Path ("section") section:String,@Query("api-key") apiKey:String)
:LiveData<ApiResponse<TimesStoriesResponse>>
}
private fun initViewModel() {
viewModel = ViewModelProviders.of(this, viewModelFactory).get(section,TimesViewModel::class.java)
}
private fun initData() {
viewModel?.fetchStories(section)?.observe(this, Observer {
when (it?.status) {
Status.LOADING -> {
showLoading(true)
showError(false,null)
}
Status.SUCCESS -> {
showLoading(false)
showError(false,null)
showSuccessData(it.data)
}
Status.ERROR -> {
showLoading(false)
showError(true,it.message)
}
}
})
}
问题:所有选项卡都显示旅行
参数的数据
TimesViewModel
class TimesViewModel @Inject constructor(private val timesRepository: TimesRepository) :
ViewModel() {
lateinit var data: LiveData<Resource<TimesStoriesResponse>>
fun fetchStories(section:String): LiveData<Resource<TimesStoriesResponse>> {
data = timesRepository.loadStories(section)
return data
}
}
注意:这两个方法都是在
TimeListFragmnet的onViewCreated()中调用的这应该是由于您的视图模型的缘故
通常,由于ViewModel
的工作方式,每个活动或片段都有一个ViewModel
。使用ViewModel
的一个主要好处是,它的生命周期与片段的生命周期完全分离,因此可以多次销毁和重新创建片段,并且您仍然能够恢复存储在ViewModel
中的当前数据
因此,这意味着使用从ViewModelProviders
获取ViewModel
的典型代码,您将获取完全相同的ViewModel
通常,这不会导致问题,但在您的ViewPager
中,您正在重用相同的TimesListFragment
,它很可能调用相同的ViewModel
,因此导致每个片段显示相同的数据
解决方案是使用:
ViewModelProviders.of(this).get(KEY, TimesViewModel::class.java)
请注意用于区分需要获取的ViewModels的键。因此,通过使用ViewPager
中的位置作为唯一键,您应该能够为每个TimesListFragment
拥有唯一的ViewModel
,您需要告诉ViewPager
不要加载当前未显示的页面。我想,默认情况下,它至少在左侧加载一页,在右侧加载一页。你能发布ApiService的代码吗?发布的ApiService代码…是的,我也有同样的问题,因为默认情况下,ViewPager
来回缓存一页。因此,一种解决方案是使用ViewPager
片段中的setUserVisibleHint()
方法来管理片段在ViewPager
中是否可见。@Jeel Vankhede:没有任何区别。我认为这与LiveDataTimeListFragment有关,每次调用TimeListFragment的onCreate()时,这意味着每次创建fragment的新实例时,都会创建TimeViewModel的新实例。我是对的吗?不,这个.get(TimesViewModel::class.java)
的工作方式是,如果它不存在,它将创建一个新的TimesViewModel
实例。但是如果它已经存在,那么它将返回现有的一个。因此,所有6个TimesListFragment
都将使用相同的ViewModel
。但是如果您使用ViewModelProviders.of(this).get(KEY,TimesViewModel::class.java)
来指定KEY
,那么您将能够创建一个属于每个TimesListFragment
的唯一ViewModel
。尝试在KEY中传递选项卡标题(科学、技术等)以区分ViewModel,不起作用:(.viewModel=ViewModelProviders.of(this,viewModelFactory).get(section,TimesViewModel::class.java)有什么建议吗?对我来说不起作用,我有两个不同的片段(从同一父级继承)生活在FragmentPagerAdapter中,在我实例化视图模型的每个片段中(与viewmodel类相同,但有2个实例)。chatRoomViewModel=ViewModelProviders.of(this).get(“KEY1”,chatRoomViewModel.class);chatRoomViewModel=ViewModelProviders.of(this).get(“KEY2”,chatRoomViewModel.class);即使我正在更改片段1中的数据,片段2中的observer方法也会被调用,有办法将其作废吗?