Использование библиотеки подкачки Android для отображения отфильтрованных результатов из тех же 2 загруженных фрагментов в ViewPager с FragmentPagerAdapter
У меня есть одно приложение активности, которое сосредоточено вокруг фрагмента, который будет перечислять данные из онлайн-API. Я использую один и тот же фрагмент в приложении, фильтруя данные по мере необходимости.
Фильтрация выполняется путем передачи параметров через Factory в DataSource. Все это прекрасно работает, если у меня загружен только один фрагмент. Я могу фильтровать и искать просто отлично.
Проблемы начинаются при попытке загрузить несколько фрагментов в ViewPager. Например, Фрагмент A - фильтруется для отображения активных элементов. Фрагмент B - фильтруется для отображения элементов с истекшим сроком. Оба должны отображаться в ViewPager с использованием FragmentPagerAdapter. Когда я запускаю приложение, оба Фрагмента будут отфильтрованы для просроченных элементов (последний фрагмент добавлен в viewpager). Кажется, параметры, которые Фрагмент A, установленный в DataSource, немедленно перезаписываются Фрагментом B. Фрагмент loadInitial работает, как и должно, но loadAfter использует параметры из фрагмента B.
Следует также отметить, что если я аннулирую () DataSource, он возвращает правильные отфильтрованные данные без проблем. (поэтому при загрузке мои параметры перезаписываются, а loadAfter использует неверный параметр)
Пробовал связываться с Обозревателем с помощью getViewLifecycleOwner(), пытаясь выяснить, если они так называют мой источник данных, это проблема, пробовал разные ViewPager Адаптеры FragmentStatePagerAdapter и FragmentPagerAdapter.
Все проверки показывают, что DataSource получает правильный параметр, а затем почти сразу же перезаписывают его.
Итак, вопрос в том, является ли вызов PageKeyedDataSource не уникальным для фрагмента, вызывающего его? Почему мои переменные перезаписываются другим фрагментом.
Может кто-нибудь сказать, где я должен искать, чтобы решить эту проблему.
Примечание: у меня есть три фрагмента, загруженных с использованием FragmentStatePagerAdapter, причем 2 из 3 - это один и тот же фрагмент, вызванный разными параметрами. Он работает нормально, потому что с тремя загруженными фрагментами FragmentStatePagerAdapter, по-видимому, не инициализирует 3-й фрагмент до тех пор, пока все не будет загружено, поэтому он не отключится по другому фрагменту.
1 ответ
Я столкнулся с той же проблемой просмотра пейджер загружает два фрагмента, следующий фрагмент переопределяет значение. Вот как я это сделал.
Во фрагменте я установил список для просмотра модели.
companion object {
private const val ARG_SECOND = "arg_second"
@JvmStatic
fun newInstance(second: Array<Pair<String, String>>): PlaceholderFragment {
return PlaceholderFragment().apply {
arguments = Bundle().apply {
putString(ARG_SECOND,second[0].second)
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProviders.of(this).get(PageViewModel::class.java).apply {
setListId(arguments?.getString(ARG_SECOND) ?: "")
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btn.setOnClickListener {
viewModel.setListId("my id")
viewModel.videosList.value?.dataSource?.invalidate()
}
}
В представлении модели я создаю метод setListId:
class PageViewModel(application: Application) : AndroidViewModel(application)
{
//paging
private val networkService = NetworkService.getService()
var videosList: LiveData<PagedList<Item>>
private val compositeDisposable = CompositeDisposable()
private val pageSize = 50
private val videosDataSourceFactory: VideosDataSourceFactory
init {
videosDataSourceFactory = VideosDataSourceFactory(compositeDisposable,
networkService)
val config = PagedList.Config.Builder()
.setPageSize(pageSize)
.setInitialLoadSizeHint(pageSize)
.setEnablePlaceholders(false)
.build()
videosList = LivePagedListBuilder<String, Item>(videosDataSourceFactory,
config).build()
}
fun getState(): LiveData<State> = Transformations.switchMap<VideosDataSource,
State>
(videosDataSourceFactory.videosDataSourceLiveData,VideosDataSource::state)
fun retry() {
videosDataSourceFactory.videosDataSourceLiveData.value?.retry()
}
fun setListId(listId: String){
videosDataSourceFactory.listId = listId
}
override fun onCleared() {
super.onCleared()
compositeDisposable.dispose()
}
fun listIsEmpty(): Boolean {
return videosList.value?.isEmpty() ?: true
}
}
В фабрике источников данных я создаю переменную:
val videosDataSourceLiveData = MutableLiveData<VideosDataSource>()
lateinit var listId:String
override fun create(): DataSource<String, Item> {
val videosDataSource = VideosDataSource(networkService,
compositeDisposable,listId)
videosDataSourceLiveData.postValue(videosDataSource)
return videosDataSource
}
А затем получить его через конструктор источника данных здесь:
class VideosDataSource(
private val networkService: NetworkService,
private val compositeDisposable: CompositeDisposable,
private val listId: String
): PageKeyedDataSource<String, Item>() {
var state: MutableLiveData<State> = MutableLiveData()
private var retryCompletable: Completable? = null
override fun loadInitial(params: LoadInitialParams<String>, callback:
LoadInitialCallback<String, Item>) {
updateState(State.LOADING)
compositeDisposable.add(
networkService.getPlaylistVideos(listId
,""
,Constants.API_KEY)
.subscribe( { response ->
updateState(State.DONE)
callback.onResult(response.items, response.prevPageToken,
response.nextPageToken)
},
{
updateState(State.ERROR)
setRetry(Action { loadInitial(params,callback) })
}
)
)
}