希望大家一切顺利。
我实现了一个简单的 Android 项目,显示美国各州列表。 为了获取状态列表,我使用 MVVM 设计模式、Repository、Retrofit、Room、viewModelScope、挂起函数和 CoroutineScope。
Repository 中的流程如下。
(1) ViewModel向viewModelScope中的Repository请求数据。
(2) Repository 尝试从 CoroutineScope 中的 SQLite 读取数据。
(3) 如果SQLite中没有数据,Repository使用Retrofit请求数据。
(4) 从服务器获取数据后,将数据保存到 CoroutineScope 中的 SQLite 中。
(5) Repository 中的所有序列都包含在 suspendCoroutine 中。
工作正常。但我不确定这是否是最好的解决方案。
这是我的 ViewModel 和 Repository 代码。
希望您检查我的代码,并让我知道更好的代码(如果存在)。
谢谢。
[ViewModel代码]==========================
class StateViewModel @Inject constructor(private val repository: StateRepository) : ViewModel() {
val ldStates = MutableLiveData<List<State>>()
// Request Card data list to Repository
fun reqStates() {
viewModelScope.launch {
val res = repository.reqStates()
withContext(Dispatchers.Main) {
res?.let { ldStates.postValue(it) }
}
}
}
}
[仓库代码]==========================
class StateRepository @Inject constructor(private var api: StateApi) {
private val db = StateDatabase.getInstance(App.context)
suspend fun reqStates(): List<State>? {
return suspendCoroutine { continuation ->
CoroutineScope(Dispatchers.IO).launch {
// Search State list in SQLite
val states = db?.stateDao()?.getAll()
if(!states.isNullOrEmpty()) {
continuation.resume(states)
} else {
// Get State list from Server
resSuspendCoroutine(continuation)
}
}
}
}
// Get State list from Server
private fun resSuspendCoroutine(continuation: Continuation<List<State>?>) {
val call: Call<List<State>> = api.states()
// Request State list to server when SQLite is empty
call.enqueue(object : Callback<List<State>> {
override fun onResponse(call: Call<List<State>>, response: Response<List<State>>) {
continuation.resume(response.body())
// Save state list in SQLite
response.body()?.let { saveStatesInDB(it) }
}
override fun onFailure(call: Call<List<State>>, t: Throwable) {
continuation.resume(null)
}
})
}
// Save state list in SQLite
private fun saveStatesInDB(states: List<State>) {
CoroutineScope(Dispatchers.IO).launch {
states.forEach { db?.stateDao()?.insert(it) }
}
}
}
我是这篇文章的作者。 我使用参数函数而不是 suspendCoroutine 简化了代码,如下所示。 (1)你觉得这样没问题吗? (2) 如果有更好的代码请告诉我。
谢谢你。
[ViewModel代码]============================
类 StateViewModel @Inject 构造函数(私有 val 存储库:StateRepository):ViewModel(){
val ldStates = MutableLiveData()
// Request Card data list to Repository
fun reqStates() {
repository.reqStates(::updateStates)
}
private fun updateStates(states: List<State>?) {
states?.let { ldStates.postValue(it) }
}
}
[存储库代码]==============================
class StateRepository @Inject 构造函数(private var api: StateApi) { private val db = StateDatabase.getInstance(App.context)
fun reqStates(update:(s:List<State>?)->Unit) {
CoroutineScope(Dispatchers.IO).launch {
// Search State list in SQLite
val states = db?.stateDao()?.getAll()
if(!states.isNullOrEmpty()) {
update(states)
} else {
// Get State list from Server
resSuspendCoroutine(update)
}
}
}
// Get State list from Server
private fun resSuspendCoroutine(update:(s:List<State>?)->Unit) {
val call: Call<List<State>> = api.states()
// Request State list to server when SQLite is empty
call.enqueue(object : Callback<List<State>> {
override fun onResponse(call: Call<List<State>>, response: Response<List<State>>) {
update(response.body())
// Save state list in SQLite
response.body()?.let { saveStatesInDB(it) }
}
override fun onFailure(call: Call<List<State>>, t: Throwable) {
update(null)
}
})
}
// Save state list in SQLite
private fun saveStatesInDB(states: List<State>) {
CoroutineScope(Dispatchers.IO).launch {
states.forEach { db?.stateDao()?.insert(it) }
}
}
}