如何使用分页库在Leanback VerticalGridSupportFragment中实现分页?

问题描述 投票:12回答:1

我们正在尝试使用体系结构组件分页库在Leanback VerticalGridSupportFragment中实现分页。依靠Leanback本身与Paging Library没有任何现成的兼容性,因此我们扩展了它的ObjectAdapter类并设法轻松实现了[[append和clear操作,但是我们很难尝试使modify操作起作用的时间。在内容修改操作期间,分页库的PagedList类使用AsyncPagedListDiffer计算差异,该AsyncPagedListDiffer在内部使用PagedStorageDiffHelper(它是程序包专用的类),并且在内部使用PagedList的程序包专用的PagedStorage字段来访问实际的基础数据。因此,由于可见性的限制,我们无法实现内部使用的与分页库相同的逻辑。我们正在寻找一种干净巧妙的方法,使Leanback与Paging一起工作,而又不提取和修改这两者的内部。这是我们的ObjectAdapter的实现,它支持追加和清除数据,但不支持内容修改。

有人曾经设法通过分页库在Leanback中实现分页吗?

class LeanbackVerticalGridPagedListAdapter<T>( presenter: Presenter, private val stubItem: T ) : ObjectAdapter(presenter) { private val mUpdateCallback = object : ListUpdateCallback { override fun onInserted(position: Int, count: Int) { notifyItemRangeInserted(position, count) } override fun onRemoved(position: Int, count: Int) { notifyItemRangeRemoved(position, count) } override fun onMoved(fromPosition: Int, toPosition: Int) { notifyItemMoved(fromPosition, toPosition) } override fun onChanged(position: Int, count: Int, payload: Any?) { notifyItemRangeChanged(position, count, payload) } } private var mPagedList: PagedList<T>? = null private var mSnapshot: PagedList<T>? = null private val mPagedListCallback = object : PagedList.Callback() { override fun onInserted(position: Int, count: Int) { mUpdateCallback.onInserted(position, count) } override fun onRemoved(position: Int, count: Int) { mUpdateCallback.onRemoved(position, count) } override fun onChanged(position: Int, count: Int) { mUpdateCallback.onChanged(position, count, null) } } override fun size(): Int = mPagedList?.size ?: mSnapshot?.size ?: 0 override fun get(index: Int): T? = mPagedList?.let { it.loadAround(index) it[index] ?: stubItem } ?: mSnapshot?.let { it[index] } ?: throw IndexOutOfBoundsException("Item count is zero, getItem() call is invalid") fun submitList(pagedList: PagedList<T>?) { if (pagedList == null) { val removedCount = size() if (mPagedList != null) { mPagedList!!.removeWeakCallback(mPagedListCallback) mPagedList = null } else if (mSnapshot != null) { mSnapshot = null } // dispatch update callback after updating mPagedList/mSnapshot mUpdateCallback.onRemoved(0, removedCount) return } if (mPagedList == null && mSnapshot == null) { // fast simple first insert mPagedList = pagedList pagedList.addWeakCallback(null, mPagedListCallback) // dispatch update callback after updating mPagedList/mSnapshot mUpdateCallback.onInserted(0, pagedList.size) return } if (mPagedList != null) { // first update scheduled on this list, so capture mPages as a snapshot, removing // callbacks so we don't have resolve to updates against a moving target mPagedList!!.removeWeakCallback(mPagedListCallback) mSnapshot = mPagedList!!.snapshot() as PagedList<T> mPagedList = null } if (mSnapshot == null || mPagedList != null) { DevUtil.crashDuringDevelopment(IllegalStateException("must be in snapshot state to diff")) } } }

android android-tv leanback android-paging-library
1个回答
0
投票
[如果有人还在寻找它,则可以通过移植PagedListAdapter使它正常工作:

import androidx.leanback.widget.ArrayObjectAdapter import androidx.leanback.widget.Presenter import androidx.leanback.widget.PresenterSelector import androidx.paging.AsyncPagedListDiffer import androidx.paging.PagedList import androidx.recyclerview.widget.AsyncDifferConfig import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListUpdateCallback /** * Base adapter class from leanback's ArrayObjectAdapter which supports paging * @link androidx.paging.PagedListAdapter * Use * @link * #submitList * methods to submit PagedList returned by paging library */ @Suppress("unused") class PagedArrayObjectAdapter<T> : ArrayObjectAdapter, ListUpdateCallback { private val logTag = PagedArrayObjectAdapter::class.java.name private val differ: AsyncPagedListDiffer<T> private val listener: AsyncPagedListDiffer.PagedListListener<T> = AsyncPagedListDiffer.PagedListListener { previousList, currentList -> @Suppress("DEPRECATION") onCurrentListChanged(currentList) onCurrentListChanged(previousList, currentList) } constructor(diffCallback: DiffUtil.ItemCallback<T>) : this( AsyncDifferConfig.Builder<T>(diffCallback).build() ) constructor(config: AsyncDifferConfig<T>) : super() { differ = AsyncPagedListDiffer(this, config) differ.addPagedListListener(listener) } constructor( presenter: Presenter, diffCallback: DiffUtil.ItemCallback<T> ) : this( presenter, AsyncDifferConfig.Builder<T>(diffCallback).build() ) constructor( presenter: Presenter, config: AsyncDifferConfig<T> ) : super(presenter) { differ = AsyncPagedListDiffer(this, config) differ.addPagedListListener(listener) } constructor( presenterSelector: PresenterSelector, diffCallback: DiffUtil.ItemCallback<T> ) : this( presenterSelector, AsyncDifferConfig.Builder<T>(diffCallback).build() ) constructor( presenterSelector: PresenterSelector, config: AsyncDifferConfig<T> ) : super( presenterSelector ) { differ = AsyncPagedListDiffer(this, config) differ.addPagedListListener(listener) } /** * @link * ListUpdateCallback#onInserted */ override fun onInserted(position: Int, count: Int) { notifyItemRangeInserted(position, count) } /** * @link * ListUpdateCallback#onRemoved */ override fun onRemoved(position: Int, count: Int) { notifyItemRangeRemoved(position, count) } /** * @link * ListUpdateCallback#onMoved */ override fun onMoved(fromPosition: Int, toPosition: Int) { notifyItemMoved(fromPosition, toPosition) } /** * @link * ListUpdateCallback#onChanged */ override fun onChanged(position: Int, count: Int, payload: Any?) { notifyItemRangeChanged(position, count, payload) } /** * Set the new list to be displayed. * * * If a list is already being displayed, a diff will be computed on a background thread, which * will dispatch Adapter.notifyItem events on the main thread. * * @param pagedList The new list to be displayed. */ fun submitList(pagedList: PagedList<T>?) { differ.submitList(pagedList) } /** * Set the new list to be displayed. * * * If a list is already being displayed, a diff will be computed on a background thread, which * will dispatch Adapter.notifyItem events on the main thread. * * * The commit callback can be used to know when the PagedList is committed, but note that it * may not be executed. If PagedList B is submitted immediately after PagedList A, and is * committed directly, the callback associated with PagedList A will not be run. * * @param pagedList The new list to be displayed. * @param commitCallback Optional runnable that is executed when the PagedList is committed, if * it is committed. */ fun submitList(pagedList: PagedList<T>?, commitCallback: Runnable?) { differ.submitList(pagedList, commitCallback) } /** * @link * ArrayObjectAdapter#get */ override fun get(index: Int): T? { return differ.getItem(index) } /** * @link * ArrayObjectAdapter#size */ override fun size(): Int { return differ.itemCount } /** * Returns the PagedList currently being displayed by the Adapter. * <p> * This is not necessarily the most recent list passed to * @link * #submitList(PagedList) * because a diff is computed asynchronously between the new list and the current list before * updating the currentList value. May be null if no PagedList is being presented. * * @return The list currently being displayed. * * @link * #onCurrentListChanged(PagedList, PagedList) */ fun getCurrentList(): PagedList<T>? = differ.currentList @Deprecated("") fun onCurrentListChanged(currentList: PagedList<T>?) { } @Suppress("MemberVisibilityCanBePrivate", "UNUSED_PARAMETER") fun onCurrentListChanged(previousList: PagedList<T>?, currentList: PagedList<T>?) { } }

© www.soinside.com 2019 - 2024. All rights reserved.