Meh*_*iya 7 android android-jetpack-compose jetpack-compose-accompanist android-jetpack-compose-pager
我的应用程序中有两个屏幕。Paging3第一个屏幕通过使用垂直网格中的库显示设备上的图像列表。现在,当用户单击图像时,我将单击位置传递到第二个屏幕,我在第二个屏幕上使用HorizontalPager伴奏来全屏显示图像。两个屏幕共享相同的 ViewModel 以使用Paging3.
在 HorizontalPager 中显示图像的代码如下所示。
val images: LazyPagingItems<MediaStoreImage> =
viewModel.getImages(initialLoadSize = args.currentImagePosition + 1, pageSize = 50)
.collectAsLazyPagingItems()
val pagerState = rememberPagerState(initialPage = currentImagePosition)
Box(modifier = modifier) {
HorizontalPager(
count = images.itemCount,
state = pagerState,
itemSpacing = 16.dp
) { page ->
ZoomableImage(
modifier = modifier,
imageUri = images[page]?.contentUri
)
}
}
Run Code Online (Sandbox Code Playgroud)
这里,currentImagePosition是在第一个屏幕上单击的图像的索引。我正在设置initialLoadSize确保currentImagePosition + 1分页库已获取要显示的单击图像。
当第二个屏幕打开时,单击的图像将按预期全屏显示。但是,当用户滑动获取下一个图像时,不会加载下一个图像,而是随着50用户进一步滑动而加载带有索引等的图像。
我不确定我在这里缺少什么。任何帮助将不胜感激。
编辑:添加了 ViewModel、存储库和分页代码
视图模型
fun getImages(initialLoadSize: Int = 50): Flow<PagingData<MediaStoreImage>> {
return Pager(
config = PagingConfig(
pageSize = 50,
initialLoadSize = initialLoadSize,
enablePlaceholders = true
)
) {
repository.getImagesPagingSource()
}.flow.cachedIn(viewModelScope)
}
Run Code Online (Sandbox Code Playgroud)
存储库
fun getImagesPagingSource(): PagingSource<Int, MediaStoreImage> {
return ImagesDataSource { limit, offset ->
getSinglePageImages(
limit,
offset
)
}
}
Run Code Online (Sandbox Code Playgroud)
private fun getSinglePageImages(limit: Int, offset: Int): List<MediaStoreImage> {
val images = ArrayList<MediaStoreImage>()
val cursor = getCursor(limit, offset)
cursor?.use {
val idColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
val dateModifiedColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_MODIFIED)
val displayNameColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)
val sizeColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE)
while (it.moveToNext()) {
val id = it.getLong(idColumn)
val dateModified =
Date(TimeUnit.SECONDS.toMillis(it.getLong(dateModifiedColumn)))
val dateModifiedString = getFormattedDate(dateModified)
val displayName = it.getString(displayNameColumn)
val size = it.getLong(sizeColumn)
val sizeInMbKb = getFileSize(size)
val contentUri = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
id
)
images.add(
MediaStoreImage(
id,
displayName,
dateModifiedString,
contentUri,
sizeInMbKb
)
)
}
}
cursor?.close()
return images
}
Run Code Online (Sandbox Code Playgroud)
private fun getCursor(limit: Int, offset: Int): Cursor? {
val projection = arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATE_MODIFIED,
MediaStore.Images.Media.SIZE
)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val bundle = bundleOf(
ContentResolver.QUERY_ARG_SQL_SELECTION to "${MediaStore.Images.Media.RELATIVE_PATH} like ? ",
ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS to arrayOf("%${context.getString(R.string.app_name)}%"),
ContentResolver.QUERY_ARG_OFFSET to offset,
ContentResolver.QUERY_ARG_LIMIT to limit,
ContentResolver.QUERY_ARG_SORT_COLUMNS to arrayOf(MediaStore.Images.Media.DATE_MODIFIED),
ContentResolver.QUERY_ARG_SORT_DIRECTION to ContentResolver.QUERY_SORT_DIRECTION_DESCENDING
)
context.contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
bundle,
null
)
} else {
context.contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
"${MediaStore.Images.Media.DATA} like ? ",
arrayOf("%${context.getString(R.string.app_name)}%"),
"${MediaStore.Images.Media.DATE_MODIFIED} DESC LIMIT $limit OFFSET $offset",
null
)
}
}
Run Code Online (Sandbox Code Playgroud)
分页数据源
class ImagesDataSource(private val onFetch: (limit: Int, offset: Int) -> List<MediaStoreImage>) :
PagingSource<Int, MediaStoreImage>() {
override fun getRefreshKey(state: PagingState<Int, MediaStoreImage>): Int? {
return state.anchorPosition?.let {
state.closestPageToPosition(it)?.prevKey?.plus(1)
?: state.closestPageToPosition(it)?.nextKey?.minus(1)
}
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MediaStoreImage> {
val pageNumber = params.key ?: 0
val pageSize = params.loadSize
val images = onFetch.invoke(pageSize, pageNumber * pageSize)
val prevKey = if (pageNumber > 0) pageNumber.minus(1) else null
val nextKey = if (images.isNotEmpty()) pageNumber.plus(1) else null
return LoadResult.Page(
data = images,
prevKey = prevKey,
nextKey = nextKey
)
}
}
Run Code Online (Sandbox Code Playgroud)
问题解决了。每当第二个屏幕打开时,getImages()就会调用共享 ViewModel 的函数,从而创建一个新的 Pager 实例。这个新的寻呼机实例与第一个屏幕上使用的不同。参考StackOverflow上的这个答案,我在ViewModel的块中创建了Pager,init如下所示。
val images: Flow<PagingData<MediaStoreImage>>
init {
images = Pager(
config = PagingConfig(
pageSize = 50,
initialLoadSize = 50,
enablePlaceholders = true
)
) {
repository.getImagesPagingSource()
}.flow.cachedIn(viewModelScope)
}
Run Code Online (Sandbox Code Playgroud)
在第二个屏幕上,我收集了分页项目,如下所示。
val lazyImages: LazyPagingItems<MediaStoreImage> = viewModel.images.collectAsLazyPagingItems()
Run Code Online (Sandbox Code Playgroud)
现在,我不必传递,initialLoadSize因为在第一个屏幕中创建的寻呼机正在被重用,它已经加载了项目。
| 归档时间: |
|
| 查看次数: |
5953 次 |
| 最近记录: |