Android 如何使用查看寻呼机2转到使用寻呼机3加载数据的位置?
我使用ViewPager2显示从服务器获取的数据,并使用Paging3库保存到房间数据库。我的问题是,如何通过代码导航到特定的视图寻呼机项目?如果我使用viewPager.setCurrentItem(position,false),那么这不起作用。例如,如果在左/右滑动时动态加载总共3000个项目,如何将位置设置为1000,然后从那里开始在两个方向上导航/加载数据?我不能让它工作 注意:在下面的DogPagingMediator类中,我也尝试在刷新块中设置一些起始编号,而不是最新(最高)的编号,但在加载应用程序时,如果数据库中本地不存在编号较高的项目,则视图寻呼机将仅在此位置启动,否则,不管刷新中返回的页面是什么,它总是从编号最高的项开始(我假设dogDao.getDogs()以降序获取数据库中的所有项) p.p.S:我之所以使用live data而不是flow,是因为flow在我刷卡时由于某种原因导致NullPointerException 包含视图寻呼机的片段中onCreateView的代码:Android 如何使用查看寻呼机2转到使用寻呼机3加载数据的位置?,android,android-viewpager2,android-paging,Android,Android Viewpager2,Android Paging,我使用ViewPager2显示从服务器获取的数据,并使用Paging3库保存到房间数据库。我的问题是,如何通过代码导航到特定的视图寻呼机项目?如果我使用viewPager.setCurrentItem(position,false),那么这不起作用。例如,如果在左/右滑动时动态加载总共3000个项目,如何将位置设置为1000,然后从那里开始在两个方向上导航/加载数据?我不能让它工作 注意:在下面的DogPagingMediator类中,我也尝试在刷新块中设置一些起始编号,而不是最新(最高)的编号
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)
}
}
从视图模型:
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示例类似,只是它按降序排序)::
@OptIn(ExperimentalPagingApi::class)
类DogPagingMediator@Inject构造函数(
专用val dogDatabase:dogDatabase,
二等兵val dogDao:dogDao,
私有val remoteKeysDao:remoteKeysDao,
私人val服务:DogService,
):RemoteMediator(){
覆盖挂起乐趣加载(加载类型:加载类型,状态:PagingState):结果{
试一试{
val page=何时(加载类型){
LoadType.REFRESH->{
val remoteKeys=getRemoteKeyClosestToCurrentPosition(状态)
remoteKeys?.nextKey?.plus(页面大小):浏览日志视图模型。最新的DogNumber
}
LoadType.PREPEND->{
val remoteKeys=getRemoteKeyForFirstItem(状态)
if(remoteKeys==null){
//LoadType是PREPEND,因此之前加载了一些数据,
//所以我们应该可以拿到遥控钥匙
//如果remoteKeys为null,那么我们是一个无效状态,我们有一个bug
抛出InvalidObjectException(“远程键和prevKey不应为null”)
}
//如果前一个键为null,则无法请求更多数据
remoteKeys.prevKey
?:返回MediatorResult.Success(endofPaginationReach=true)
remoteKeys.prevKey
}
LoadType.APPEND->{
val remoteKeys=getRemoteKeyForLastItem(状态)
if(remoteKeys?.nextKey==null){
抛出InvalidObjectException(“远程键对于$loadType不应为null”)
}
remoteKeys.nextKey
}
}
val dogs:MutableList=mutableListOf()
用于(从第i页到第i页-页面大小){
试一试{
val响应=service.geDogWithNumber(i)
dogs.add(从DTO转换为(响应))
}捕获(例如:HttpException){
//当请求狗超出范围时将为404
如果(例如代码()!=404){
投手
}
}
}
val endofpaginationreach=dogs.isEmpty()
dogDatabase.withTransaction{
val prevKey=
如果(页面==BrowseDogsViewModel.latestDogNumber)为空,则页面+页面大小
val nextKey=if(endofPaginationReach)null else页面-页面大小
val keys=dogs.map{
RemoteKey(dogNum=it.number,prevKey=prevKey,nextKey=nextKey)
}
remoteKeysDao.insertAll(键)
dogDao.insertAll(狗)
}
返回结果。成功(
EndofPaginationReach=EndofPaginationReach
)
}捕获(异常:IOException){
返回中介结果。错误(异常)
}捕获(异常:HttpException){
返回中介结果。错误(异常)
}
}
private suspend fun getRemoteKeyForLastItem(状态:PagingState):RemoteKeys{
//获取检索到的最后一个包含项的页面。
//从最后一页,获取最后一项
返回状态.pages.lastOrNull{it.data.isNotEmpty()}?.data?.lastOrNull()
?让{狗->
//获取检索到的最后一项的远程密钥
remoteKeysDao.remoteKeysDogNum(dog.number)
}
}
private suspend fun getRemoteKeyForFirstItem(状态:PagingState):RemoteKeys{
//获取检索到的第一个包含项的页面。
//从第一页中,获取第一项
返回state.pages.firstOrNull{it.data.isNotEmpty()}?.data?.firstOrNull()
?让{狗->
//获取检索到的第一个项目的远程密钥
remoteKeysDao.remoteKeysDogNum(dog.number)
}
}
私有挂起功能getRemoteKeyClosestToCurrentPosition(
状态:分页状态
):遥控钥匙{
//分页库正在尝试在定位点位置之后加载数据
//获取最靠近锚定位置的项目
返回状态.anchorPosition?.let{position->
state.closestItemToPosition(位置)?.number?.let{num->
remoteKeysDao.remoteKeysDogNum(num)
}
}
}
私人娱乐中心(狗)
@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()
}
}
}