Jetpack Compose类别数据缓存问题:重复点击避免重复请求
最优临时数据缓存方案(Jetpack Compose)
核心思路
用ViewModel内的内存缓存存储已加载的类别图片数据——ViewModel生命周期与页面绑定,能在页面存活期间保留缓存,且不会因配置变更丢失。推荐用MutableMap<String, List<Image>>(假设Image是你的图片数据类)按类别Key存储对应数据,请求前先查缓存,存在则直接返回,不存在再发起网络请求。
代码实现示例
ViewModel层
class GalleryViewModel(private val repository: GalleryRepository) : ViewModel() { // 内存缓存:类别ID -> 对应图片列表 private val categoryImageCache = mutableMapOf<String, List<Image>>() private val _imagesState = MutableStateFlow<UiState<List<Image>>>(UiState.Idle) val imagesState: StateFlow<UiState<List<Image>>> = _imagesState fun loadImagesByCategory(categoryId: String) { // 先检查缓存,存在则直接返回 categoryImageCache[categoryId]?.let { cachedImages -> _imagesState.value = UiState.Success(cachedImages) return } // 缓存不存在,发起网络请求 viewModelScope.launch { _imagesState.value = UiState.Loading runCatching { repository.getImagesByCategory(categoryId) }.onSuccess { images -> // 将新数据写入缓存 categoryImageCache[categoryId] = images _imagesState.value = UiState.Success(images) }.onFailure { _imagesState.value = UiState.Error(it.message ?: "加载失败") } } } // 通用UI状态密封类 sealed class UiState<out T> { object Idle : UiState<Nothing>() object Loading : UiState<Nothing>() data class Success<out T>(val data: T) : UiState<T>() data class Error(val message: String) : UiState<Nothing>() } }
Compose Screen层
@Composable fun GalleryScreen(viewModel: GalleryViewModel = viewModel()) { val imagesState by viewModel.imagesState.collectAsState() var selectedCategory by remember { mutableStateOf("default") } Column { // 类别选择LazyRow LazyRow { items(categories) { category -> CategoryItem( category = category, isSelected = category.id == selectedCategory, onClick = { selectedCategory = category.id viewModel.loadImagesByCategory(category.id) } ) } } // 图片展示LazyColumn when (imagesState) { GalleryViewModel.UiState.Idle -> Text("请选择类别") GalleryViewModel.UiState.Loading -> CircularProgressIndicator() is GalleryViewModel.UiState.Success -> { LazyColumn { items((imagesState as GalleryViewModel.UiState.Success).data) { image -> ImageItem(image = image) } } } is GalleryViewModel.UiState.Error -> { Text((imagesState as GalleryViewModel.UiState.Error).message) } } } }
进阶优化方案
如果需要限制缓存大小或管理更多数据,可改用LruCache替代普通Map:
// 在ViewModel中初始化LruCache private val imageCache = LruCache<String, List<Image>>( maxSize = 5 * 1024 * 1024 // 5MB,可根据实际数据体积调整 ) // 读取缓存 imageCache.get(categoryId)?.let { cachedImages -> _imagesState.value = UiState.Success(cachedImages) return } // 写入缓存 imageCache.put(categoryId, images)
常见问题规避
- 旧数据问题:每次写入缓存时必须用最新网络请求结果覆盖对应Key的缓存,禁止追加或复用旧数据。
- 空列表问题:若网络请求返回空列表,也要写入缓存,避免重复请求;如需区分“无数据”和“未请求”,可在
UiState中新增Empty状态。 - 配置变更问题:ViewModel自带的内存缓存会在旋转屏幕等配置变更时自动保留,无需额外处理。
内容的提问来源于stack exchange,提问作者AhmadAB
相关产品推荐
相关产品推荐

