使用Retrofit2+Jetpack Compose添加数据后,如何最优刷新服务器数据?
Jetpack Compose + Retrofit2 数据添加后列表刷新最优方案
在Jetpack Compose场景下使用Retrofit2实现数据增查操作时,添加新数据返回列表页后,新数据无法实时显示——原因是页面初始化时API请求已完成,仅重启应用才能读取到新数据。以下是几种最优刷新方案:
一、直接触发刷新(最易实现)
在数据添加操作成功后,主动调用列表数据的API请求方法,强制拉取最新数据。
代码修改示例
ViewModel中添加数据的方法内,成功回调后调用刷新:
// 假设添加数据的UseCase调用逻辑 fun addCampaign(campaign: Campaign) { addCampaignUseCase(campaign).onEach { response -> when (response) { is Resource.Success -> { // 添加成功后立即刷新列表数据 getCampaigns() } is Resource.Loading -> { /* 加载状态处理 */ } is Resource.Error -> { /* 错误状态处理 */ } } }.launchIn(viewModelScope) }
Composable中通过收集ViewModel的StateFlow自动更新UI:
@Composable fun CampaignListScreen(viewModel: CampaignViewModel = hiltViewModel()) { val currentCampaigns by viewModel.campaignListCurrent.collectAsState() val completedCampaigns by viewModel.campaignListCompleted.collectAsState() val isLoading by viewModel.isLoadingProgressBar.collectAsState() // 列表UI渲染逻辑... }
二、用SharedFlow实现刷新触发器
通过SharedFlow作为刷新事件的触发器,避免在每个数据修改操作后重复调用刷新方法,实现解耦。
代码修改示例
ViewModel中定义触发器并监听:
private val refreshTrigger = MutableSharedFlow<Unit>(replay = 0) val campaignListCurrent = MutableStateFlow<List<Campaign>>(emptyList()) val campaignListCompleted = MutableStateFlow<List<Campaign>>(emptyList()) val isLoadingProgressBar = MutableStateFlow(false) init { viewModelScope.launch { // 监听刷新事件,触发时重新拉取数据 refreshTrigger.collect { getCampaigns() } } } // 对外暴露的刷新触发方法 fun triggerRefresh() { viewModelScope.launch { refreshTrigger.emit(Unit) } } // 添加数据成功后触发刷新 fun addCampaign(campaign: Campaign) { addCampaignUseCase(campaign).onEach { response -> if (response is Resource.Success) triggerRefresh() }.launchIn(viewModelScope) }
三、服务器推送实现实时同步(类似Firebase)
如果需要类似Firebase实时数据库的自动同步效果,需要后端支持WebSocket或Server-Sent Events(SSE),服务器数据变更时主动推送给客户端,无需客户端主动轮询。
SSE实现示例
- 添加依赖:
implementation "com.squareup.retrofit2:adapter-rxjava3:2.9.0" implementation "io.reactivex.rxjava3:rxjava:3.1.5"
- 定义SSE接口:
interface ApiServices { @GET("campaigns/sse") fun getCampaignsSse(): Observable<CampaignUpdate> }
- ViewModel中监听推送更新:
fun observeRealTimeUpdates() { apiServices.getCampaignsSse() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ update -> // 根据服务器推送的更新类型修改本地列表 when (update.type) { UpdateType.ADD -> { val updatedList = campaignListCurrent.value.toMutableList() updatedList.add(update.campaign) campaignListCurrent.value = updatedList } UpdateType.DELETE -> { val updatedList = campaignListCurrent.value.filter { it.id != update.campaign.id } campaignListCurrent.value = updatedList } } }, { error -> // 处理连接错误,比如尝试重连 }) }
四、优化本地数据维护:用StateFlow持有完整列表
避免手动维护MutableList导致的数据不同步,直接用StateFlow持有完整的列表数据,每次刷新直接替换列表,Composable通过收集StateFlow自动更新UI。
代码修改示例
ViewModel的getCampaigns()方法优化:
private fun getCampaigns() { getCampaignsUseCase().onEach { response -> when (response) { is Resource.Loading -> { isLoadingProgressBar.value = true } is Resource.Success -> { isLoadingProgressBar.value = false // 直接替换列表数据,避免手动增删 val currentData = response.data?.data?.current?.items?.data.orEmpty().drop(1) val completedData = response.data?.data?.completed?.items?.data.orEmpty().drop(1) campaignListCurrent.value = currentData campaignListCompleted.value = completedData } is Resource.Error -> { isLoadingProgressBar.value = false // 错误日志处理... } } }.launchIn(viewModelScope) }
内容的提问来源于stack exchange,提问作者Ahmed Rabee
相关产品推荐
相关产品推荐

