ViewPager с viewmodel и живыми данными, все данные 6 вкладок заменяются данными последней вкладки - PullRequest
0 голосов
/ 25 февраля 2019

Я работаю над ViewPager с 6 tabs, где у него есть только один фрагмент TimesListFragment

В зависимости от аргументов, переданных TimesListFragment, он вызывает api eg;наука, технологии, путешествия и т. д.

Я следовал указаниям Google GithubBrowserSample для своего приложения

У меня 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]
    }
}

проблема: на всех вкладках отображаются данные 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
    }
}

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

            }
        })
    }

примечание: оба метода вызываютсяв onViewCreated () из TimesListFragmnet

1 Ответ

0 голосов
/ 25 февраля 2019

Это должно происходить из-за вашего ViewModel.

Как правило, есть один ViewModel на Activity или Fragment, из-за способа, которым ViewModel предназначен для работы.Одним из основных преимуществ использования ViewModel является то, что его жизненный цикл полностью отделен от жизненного цикла вашего Fragment, поэтому ваш Fragment может быть уничтожен и воссоздан несколько раз, и вы все равно сможете восстановить текущийданные, которые хранятся в вашем ViewModel.

Следовательно, это означает, что с типичным кодом для извлечения ViewModel из ViewModelProviders вы будете получать точно такой же ViewModel.

Как правило, это не вызовет проблем, но в вашем ViewPager вы повторно используете тот же TimesListFragment, который наиболее вероятно вызывает тот же ViewModel,поэтому каждый фрагмент показывает одинаковые данные.

Решением для этого является использование:

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

Обратите внимание на КЛЮЧ, который используется для разграничения между ViewModels, которые должны быть выбраны.Таким образом, используя позиции в ViewPager в качестве уникального ключа, вы должны иметь возможность иметь уникальный ViewModel для каждого TimesListFragment.

...