具有ViewModel和实时数据的ViewPager,所有6个标签数据都被最后一个标签数据替换 [英] ViewPager with viewmodel and live data , all 6 tabs data is replaced by last tab data

查看:371
本文介绍了具有ViewModel和实时数据的ViewPager,所有6个标签数据都被最后一个标签数据替换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用6 tabsViewPager,其中只有一个片段TimesListFragment

I am working on a ViewPager with 6 tabs where it has only one fragment TimesListFragment

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

Depending on the arguments passed to TimesListFragment it calls api eg; science , technology, travel etc

对于我的应用程序,我一直遵循Google的GithubBrowserSample

I have followed Google's GithubBrowserSample for my app

我有TimesListFragment-> TimesViewModel-> TimesRepository

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

There are 6 tabs , when I hit the api all the tabs show the same result which if of the last 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]
    }
}

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

issue : all tabs shows data of travel arguments

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

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

ApiService.kt

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

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

            }
        })
    }

注意:两种方法都在TimesListFragmnet

note : both methods are called in onViewCreated() of TimesListFragmnet

推荐答案

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

This should be happening due to your ViewModel.

通常,由于ViewModel的工作方式,每个ActivityFragment有一个ViewModel.使用ViewModel的主要好处之一是它的生命周期与Fragment的生命周期完全分开,因此,您的Fragment可以被破坏并重新创建多次,并且仍然可以恢复当前版本. ViewModel中存储的数据.

Typically, there's one ViewModel per Activity or Fragment, due to the way a ViewModel is designed to work. One of the major benefits in using a ViewModel is that it's lifecycle is completely separate from the lifecycle of your Fragment, therefore, your Fragment can be destroyed and recreated multiple times and you'll still be able to restore current data that's stored in your ViewModel.

因此,这意味着使用从ViewModelProviders获取ViewModel的典型代码,您将获取完全相同的ViewModel.

Therefore, this means that with the typical code to fetch the ViewModel from the ViewModelProviders, you'll be fetching the exact same ViewModel.

通常,这不会引起问题,但是在您的ViewPager中,您正在重用相同的TimesListFragment,这很可能是 调用相同的ViewModel,因此每个片段显示相同的数据.

Typically, this won't cause a problem, but in your ViewPager, you're reusing the same TimesListFragment which is most likely calling up the same ViewModel, therefore causing each fragment to show the same data.

解决方案是使用:

ViewModelProviders.of(this).get(KEY, TimesViewModel::class.java)

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

Note the KEY which is used to differentiate between the ViewModels that needs to be fetched. So by using the positions in the ViewPager as a unique key, you should be able to have a unique ViewModel for each TimesListFragment.

这篇关于具有ViewModel和实时数据的ViewPager,所有6个标签数据都被最后一个标签数据替换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆