我在 Android 中使用新的 Paging 3 库时遇到问题,因为它一次加载所有页面。看了这篇文章:Android Paging (3) load all pages on once
但在我的情况下,RecyclerView 不在任何无限滚动器(嵌套)内,而只是在父级 ConstraintLayout 内,并且它正在水平滚动!我已经尝试了很多东西,考虑返回我的默认实现(不使用这个漂亮的 API)。这是我的代码示例:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/clDashboardMain"
android:background="@color/white"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/spacing_24"
android:clipToPadding="false"
android:orientation="horizontal"
android:paddingStart="@dimen/spacing_24"
android:paddingEnd="@dimen/spacing_24"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
我的存储库:
override fun getData(latitude: Double, longitude: Double): LiveData<PagingData<DataPost>> {
return Pager(
config = PagingConfig(
pageSize = NETWORK_PAGE_SIZE, //is 20!
enablePlaceholders = false
),
pagingSourceFactory = {
GetPagingSource(myApiService = myApiService, latitude = latitude, longitude = longitude)
}
).liveData
}
我的 PagingSource 文件:
private const val INITIAL_LOAD_SIZE = 1
class GetPagingSource(
private val myApiService: MyApiService,
private val latitude: Double,
private val longitude: Double
) : PagingSource<Int, DataPost>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, DataPost> {
// Retrofit calls that return the body type throw either IOException for network
// failures, or HttpException for any non-2xx HTTP status codes. This code reports all
// errors to the UI, but you can inspect/wrap the exceptions to provide more context.
return try {
// Key may be null during a refresh, if no explicit key is passed into Pager
// construction. Use 1 as default, because our API is indexed started at index 0
val pageNumber = params.key ?: INITIAL_LOAD_SIZE
// Suspending network load via Retrofit. This doesn't need to be wrapped in a
// withContext(Dispatcher.IO) { ... } block since Retrofit's Coroutine
// CallAdapter dispatches on a worker thread.
val response = myApiService.getData(latitude = latitude, longitude = longitude, page= pageNumber)
// Since 0 is the lowest page number, return null to signify no more pages should be loaded before it.
val prevKey = if (pageNumber == INITIAL_LOAD_SIZE) null else pageNumber - 1
// This API defines that it's out of data when a page returns empty. When out of data, we return `null` to signify no more pages should be loaded
val nextKey = if (response.data.isNotEmpty()) pageNumber + 1 else null
LoadResult.Page(
data = response.data.filter { it.coordinates.longitude > 0.0 },
prevKey = prevKey,
nextKey = nextKey
)
} catch (e: IOException) {
LoadResult.Error(e)
} catch (e: HttpException) {
LoadResult.Error(e)
}
}
override fun getRefreshKey(state: PagingState<Int, DataPost>): Int? {
return state.anchorPosition?.let {
state.closestPageToPosition(it)?.prevKey?.plus(1)
?: state.closestPageToPosition(it)?.nextKey?.minus(1)
}
}
}
我的视图模型:
//live data use case
fun getData(latitude: Double, longitude: Double): LiveData<PagingData<DataPostUIWrapper>> {
val currentLoggedUser = profileContract.getUserProfileId()
return postsContract.getPublicPosts(latitude, longitude)
.map {
it.map { dataPost ->
DataPostUIWrapper(dataPost, dataPost.isLikedBy(currentLoggedUser))
}
}
.cachedIn(viewModelScope)
}
观察用户界面:
viewModel.getData(latitude = userLocation.latitude, longitude = userLocation.longitude).observe(viewLifecycleOwner, {
lifecycleScope.launch {
myAdapter.submitData(it)
}
})