Android撰写分页3 -一次加载所有页面,无需在LazyColumn中滚动,具有网络调用,没有内部滚动

42fyovps  于 2024-01-04  发布在  Android
关注(0)|答案(1)|浏览(147)

我正在做一个Android Compose项目,我使用Paging 3沿着LazyColumn来显示从网络调用中获取的项目列表。Paging 3的默认行为是在用户滚动时加载基于prefetchDistance的页面,但在我的情况下,它加载了大约15个页面,每个包含10个记录启动屏幕。我试过设置prefetchDistace为10,但它不工作。
代码如下:ViewModel

  1. class ShowAllNotificationsViewModel @Inject constructor(private val pagingSource: NotificationPagingSource) :
  2. BaseViewModel() {
  3. private val _uiState =
  4. MutableStateFlow<UIState<BaseResponseModel<NotificationResponseModel?>>>(UIState.StateLoading)
  5. val uiState = _uiState.asStateFlow()
  6. private val _isRefreshing = MutableStateFlow(false)
  7. val isRefreshing = _isRefreshing.asStateFlow()
  8. val items: Flow<PagingData<NotificationModel>> = Pager(
  9. config = PagingConfig(
  10. pageSize = 10,
  11. prefetchDistance = 5,
  12. enablePlaceholders = false,
  13. ),
  14. pagingSourceFactory = { pagingSource }
  15. )
  16. .flow
  17. .cachedIn(viewModelScope)
  18. fun refreshData() {
  19. pagingSource.invalidate()
  20. }
  21. }

字符串

页面来源:

  1. class NotificationPagingSource @Inject constructor(val requestNotificationsUseCase: GetNotificationsUseCase) :
  2. PagingSource<String, NotificationModel>() {
  3. override suspend fun load(params: LoadParams<String>): LoadResult<String, NotificationModel> {
  4. Timber.e(IllegalStateException())
  5. Timber.d("load params = $params")
  6. val responseModel = requestNotificationsUseCase(params.key)
  7. val result = responseModel?.getAsResult();
  8. result?.let {
  9. return@load when (result) {
  10. is Result.Error<*>,
  11. Result.Loading,
  12. is Result.SessionTimeoutError<*> -> {
  13. LoadResult.Error(
  14. SessionTimeoutException()
  15. )
  16. }
  17. is Result.Success -> {
  18. LoadResult.Page(
  19. result.value.data?.notifications ?: listOf(),
  20. prevKey = null,
  21. nextKey = result.value.data?.lastId,
  22. )
  23. }
  24. }
  25. }
  26. return LoadResult.Error(
  27. IllegalStateException()
  28. )
  29. }
  30. override fun getRefreshKey(state: PagingState<String, NotificationModel>): String? {
  31. Timber.d("getRefreshKey = state = $state")
  32. return null
  33. }
  34. }

用户界面:

  1. @Composable
  2. fun ShowAllNotificationCompose(items: LazyPagingItems<NotificationModel>) {
  3. Column(
  4. modifier = Modifier
  5. .fillMaxSize()
  6. .background(Color.Black)
  7. ) {
  8. Timber.d("ShowAllNotificationCompose : state = ${items.loadState}")
  9. HeaderCompose()
  10. Box(
  11. modifier = Modifier
  12. .weight(1f)
  13. ) {
  14. val listState = rememberLazyListState()
  15. LazyColumn(
  16. modifier = Modifier,
  17. state = listState
  18. ) {
  19. items(
  20. count = items.itemCount,
  21. key = {
  22. items[it]?.id ?: 0
  23. }
  24. ) {
  25. val notificationModel = items[it]
  26. if (notificationModel != null) {
  27. NotificationItem(item = notificationModel)
  28. } else {
  29. NotificationShimmerItem()
  30. }
  31. }
  32. if (items.loadState.append == LoadState.Loading) {
  33. items(2) {
  34. NotificationShimmerItem()
  35. }
  36. }
  37. }
  38. }
  39. }
  40. }
  41. }


有没有一种方法可以修改这个设置,以确保分页请求只在到达prefectchDistance后调用。提前感谢。

lbsnaicq

lbsnaicq1#

问题出在key上:

  1. key = { items[it]?.id ?: 0 }

字符串
当您调用LazyPagingItems::get时,它会通知Paging可以触发页面加载的项目访问。从文档:
返回在指定位置呈现的项,通知Paging该项访问以触发完成prefetchDistance所需的任何加载。
而且key会立即调用所有的项目,而不仅仅是在它们显示的时候。所以对于key,你应该使用peek函数。或者你可以使用itemKey,它在内部使用peek。

  1. key = { items.peek(it)?.id ?: 0 }
  2. key = items.itemKey { it.id }

相关问题