gpt4 book ai didi

android - 如何使用 View 寻呼机 2 转到使用分页 3 加载数据的位置?

转载 作者:行者123 更新时间:2023-12-04 23:41:01 25 4
gpt4 key购买 nike

我正在使用 ViewPager2 显示从服务器获取并使用 Paging 3 库保存到 Room 数据库的数据。我的问题是,如何通过代码导航到特定的 View 寻呼机项目?如果我使用 viewPager.setCurrentItem(position, false) 那么这不起作用。例如,如果我在向左/向右滑动时动态加载总共 3000 个项目,我如何将位置设置为 1000,然后从那里在两个方向上导航/加载数据?我不能让它工作。
P.S:在下面的 DogPagingMediator 类中,我还尝试在刷新 block 中设置一些起始数字而不是最新(最高)数字,但是在加载应用程序时,如果更高编号的项目没有,则 View 寻呼机只会在此位置开始' t 在数据库中本地存在,否则它将始终从编号最高的项目开始,而不管刷新中返回的页面如何(我假设因为 dogDao.getDogs() 按降序获取数据库中的所有项目)。
P.P.S:我使用实时数据而不是流的原因是因为流在我滑动时由于某种原因导致 NullPointerException。
包含 View 寻呼机的 fragment 中的 onCreateView 代码:

    lifecycleScope.launch {
// Fetch the latest dog item from the network (data is sorted by descending)
if (!browseDogsViewModel.latestDogIsFetched()) {
browseDogsViewModel.setLatestDogNumber()
}

browseDogsViewModel.pagingDataStream.observe(viewLifecycleOwner) {
adapter.submitData(viewLifecycleOwner.lifecycle, it)
}
}
从 View 模型:
val pagingDataStream = repository.getAllDogsPagingData()

suspend fun setLatestDogNumber() {
latestDogNumber = repository.getLatestDogNumber()
}
从存储库:
fun getAllDogsPagingData() = Pager(
config = PagingConfig(pageSize = PAGE_SIZE),
remoteMediator = dogPagingMediator,
pagingSourceFactory = { dogDao.getDogs() }
).liveData
调解器(类似于 google 的 paging3 codelab 示例,但按降序排序): https://codelabs.developers.google.com/codelabs/android-paging/#0 ):
@OptIn(ExperimentalPagingApi::class)
class DogPagingMediator @Inject constructor(
private val dogDatabase: DogDatabase,
private val dogDao: DogDao,
private val remoteKeysDao: RemoteKeysDao,
private val service: DogService,
) : RemoteMediator<Int, Dog>() {
override suspend fun load(loadType: LoadType, state: PagingState<Int, Dog>): MediatorResult {
try {
val page = when (loadType) {
LoadType.REFRESH -> {
val remoteKeys = getRemoteKeyClosestToCurrentPosition(state)
remoteKeys?.nextKey?.plus(PAGE_SIZE) ?: BrowseDogsViewModel.latestDogNumber
}
LoadType.PREPEND -> {
val remoteKeys = getRemoteKeyForFirstItem(state)
if (remoteKeys == null) {
// The LoadType is PREPEND so some data was loaded before,
// so we should have been able to get remote keys
// If the remoteKeys are null, then we're an invalid state and we have a bug
throw InvalidObjectException("Remote key and the prevKey should not be null")
}
// If the previous key is null, then we can't request more data
remoteKeys.prevKey
?: return MediatorResult.Success(endOfPaginationReached = true)
remoteKeys.prevKey
}
LoadType.APPEND -> {
val remoteKeys = getRemoteKeyForLastItem(state)
if (remoteKeys?.nextKey == null) {
throw InvalidObjectException("Remote key should not be null for $loadType")
}
remoteKeys.nextKey
}
}

val dogs: MutableList<Dog> = mutableListOf()
for (i in page downTo page - PAGE_SIZE) {
try {
val response = service.geDogWithNumber(i)
dogs.add(convertFromDto(response))
} catch (ex: HttpException) {
// Will be 404 when requesting a dog out of range
if (ex.code() != 404) {
throw ex
}
}
}

val endOfPaginationReached = dogs.isEmpty()

dogDatabase.withTransaction {
val prevKey =
if (page == BrowseDogsViewModel.latestDogNumber) null else page + PAGE_SIZE
val nextKey = if (endOfPaginationReached) null else page - PAGE_SIZE
val keys = dogs.map {
RemoteKeys(dogNum = it.number, prevKey = prevKey, nextKey = nextKey)
}

remoteKeysDao.insertAll(keys)
dogDao.insertAll(dogs)
}

return MediatorResult.Success(
endOfPaginationReached = endOfPaginationReached
)
} catch (exception: IOException) {
return MediatorResult.Error(exception)
} catch (exception: HttpException) {
return MediatorResult.Error(exception)
}
}

private suspend fun getRemoteKeyForLastItem(state: PagingState<Int, Dog>): RemoteKeys? {
// Get the last page that was retrieved, that contained items.
// From that last page, get the last item
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { dog->
// Get the remote keys of the last item retrieved
remoteKeysDao.remoteKeysDogNum(dog.number)
}
}

private suspend fun getRemoteKeyForFirstItem(state: PagingState<Int, Dog>): RemoteKeys? {
// Get the first page that was retrieved, that contained items.
// From that first page, get the first item
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { dog->
// Get the remote keys of the first items retrieved
remoteKeysDao.remoteKeysDogNum(dog.number)
}
}

private suspend fun getRemoteKeyClosestToCurrentPosition(
state: PagingState<Int, Dog>
): RemoteKeys? {
// The paging library is trying to load data after the anchor position
// Get the item closest to the anchor position
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.number?.let { num ->
remoteKeysDao.remoteKeysDogNum(num)
}
}
}

private fun convertFromDto(dogDto: DogDto): Dog {
return Dog(...)
}
}
适配器:
class DogPagingAdapter() :
PagingDataAdapter<Dog, DogPagingAdapter.ViewPagerViewHolder>(DogDiffUtilCallback) {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewPagerViewHolder {
return ViewPagerViewHolder(
ItemDogViewPagerBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}

override fun onBindViewHolder(holder: ViewPagerViewHolder, position: Int) {
holder.bind(getItem(position))
}

inner class ViewPagerViewHolder(private val binding: ItemDogViewPagerBinding) :
RecyclerView.ViewHolder(binding.root) {

fun bind(dog: Dog?) {
binding.dog = dog
binding.executePendingBindings()
}
}
}

最佳答案

官方文档说:

Set the currently selected page. If the ViewPager has already beenthrough its first layout with its current adapter there will be asmooth animated transition between the current item and the specifieditem. Silently ignored if the adapter is not set or empty. Clampsitem to the bounds of the adapter.


在调用此方法之前,您必须确保适配器中存在第 N 个项目。

关于android - 如何使用 View 寻呼机 2 转到使用分页 3 加载数据的位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64958908/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com