如何借助Room与Retrofit简化MVVM架构的Repository函数
Android MVVM中Repository协程代码简化方案
原代码问题分析
原代码逻辑可行,但存在协程层级冗余(手动嵌套CoroutineScope+suspendCoroutine)、Retrofit回调与协程混用的问题,导致代码可读性差,还存在手动创建CoroutineScope引发的生命周期泄漏风险。
优化后完整代码
1. 改造Retrofit接口(支持协程)
interface StateApi { // 将原Call<T>改为suspend函数,Retrofit自动处理协程调度 @GET("states") suspend fun states(): List<State> }
2. 简化后的ViewModel
class WeatherViewModel @Inject constructor(private val stateRepository: StateRepository) : ViewModel() { val ldStates = MutableLiveData<List<State>?>() val ldWeather = MutableLiveData<Weather>() fun reqStates() { viewModelScope.launch { // viewModelScope默认在Main线程,获取结果后直接更新LiveData val res = stateRepository.reqStates() ldStates.value = res } } }
3. 简化后的Repository
open class StateRepository @Inject constructor( private val api: StateApi, private val db: StateDatabase ) { private val stateDao = db.stateDao() suspend fun reqStates(): List<State>? { // 统一切换到IO线程执行数据库查询和网络请求 return withContext(Dispatchers.IO) { // 先查询本地数据库 val localStates = stateDao.getAll() if (!localStates.isNullOrEmpty()) { localStates } else { try { // 发起网络请求获取数据 val remoteStates = api.states() // 保存数据到本地数据库 saveStatesInDB(remoteStates) remoteStates } catch (e: Exception) { // 网络请求失败时返回null null } } } } // 改为suspend函数,在IO线程执行数据库操作 private suspend fun saveStatesInDB(states: List<State>) { // 建议使用批量插入优化性能,需对应修改Dao的insert方法 stateDao.insertAll(states) } }
核心优化点
- Retrofit协程化:将接口从
Call<List<State>>改为suspend fun,彻底消除回调嵌套,Retrofit自动处理网络请求的线程调度。 - 移除冗余协程层级:删掉原代码中手动创建
CoroutineScope+suspendCoroutine的嵌套结构,利用suspend函数特性,通过withContext(Dispatchers.IO)统一调度IO操作,代码结构更简洁。 - 数据库操作规范化:将
saveStatesInDB改为suspend函数,避免手动创建无生命周期绑定的CoroutineScope,消除泄漏风险。 - ViewModel逻辑简化:
viewModelScope.launch默认运行在Main线程,获取结果后直接用ldStates.value = res更新LiveData,无需额外切换线程。 - 异常统一处理:给网络请求添加
try-catch,统一捕获异常并返回null,避免意外崩溃。
内容的提问来源于stack exchange,提问作者Denis Jung
相关产品推荐
相关产品推荐

