具有ViewModel和实时数据的ViewPager,所有6个标签数据都被最后一个标签数据替换

kar*_*nji 6 android android-viewpager android-livedata android-viewmodel

我对工作ViewPager有6个tabs地方只有一个片段TimesListFragment

根据传递给TimesListFragment它的参数调用api eg; 科学,技术,旅行等

我已经GithubBrowserSample为我的应用关注了Google的

我有TimesListFragment-> TimesViewModel->TimesRepository

有6个标签,当我点击api时,所有标签都显示相同的结果,如果最后一个 argument

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]
    }
}
Run Code Online (Sandbox Code Playgroud)

问题:所有选项卡都显示travel参数数据

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
    }
}
Run Code Online (Sandbox Code Playgroud)

TimesRepository.kt

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()
    }
Run Code Online (Sandbox Code Playgroud)

ApiService.kt

interface ApiService {
    @GET("svc/topstories/v2/{section}.json?")
    fun getTopStories(@Path ("section") section:String,@Query("api-key") apiKey:String)
            :LiveData<ApiResponse<TimesStoriesResponse>>
}
Run Code Online (Sandbox Code Playgroud)

TimesListFragment.kt

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)
                }

            }
        })
    }
Run Code Online (Sandbox Code Playgroud)

注意:两种方法都在的onViewCreated()中调用 TimesListFragmnet

Jac*_*key 14

这应该是由于您的情况而发生的ViewModel

通常,由于a 的设计工作方式,ViewModel每个Activity或都有一个。使用a的主要好处之一是它的生命周期与您的生命周期完全分开,因此,您可以多次销毁和重新创建您的生命,并且仍然可以恢复存储在其中的当前数据。FragmentViewModelViewModelFragmentFragmentViewModel

因此,这意味着,典型的代码来获取ViewModelViewModelProviders,你会获取完全相同的ViewModel

通常,这不会造成问题,但是在您的中ViewPager,您正在重用相同的内容TimesListFragment,而最有可能调用的是相同的内容ViewModel,因此导致每个片段显示相同的数据。

解决方案是使用:

ViewModelProviders.of(this).get(KEY, TimesViewModel::class.java)
Run Code Online (Sandbox Code Playgroud)

请注意KEY,该键用于区分需要获取的ViewModel。因此,通过使用中的位置ViewPager作为唯一键,您应该能够ViewModel为每个设置唯一TimesListFragment

  • 尝试在 KEY 中传递选项卡标题(科学、技术等)来区分 ViewModel ,但没有奏效:(. viewModel = ViewModelProviders.of(this, viewModelFactory).get(section,TimesViewModel::class.java) (3认同)
  • 对我来说不起作用,我有 2 个不同的片段(继承自同一个父级),它们住在 FragmentPagerAdapter 中,在每个片段中我实例化视图模型(相同的视图模型类,但有 2 个实例)。chatRoomViewModel = ViewModelProviders.of(this).get("KEY1", ChatRoomViewModel.class); chatRoomViewModel = ViewModelProviders.of(this).get("KEY2", ChatRoomViewModel.class); 即使我改变了fragment 1中的数据,fragment2中的观察者方法被调用,有没有办法使它无效? (2认同)