如何解决如何第一次忽略空数据库结果并在应用程序中等待服务器结果?
我的应用程序使用房间作为数据库并改造为网络调用 api。 我仅将数据库视为单一的事实来源。一切正常。但我没有找到一种情况的解决方案。 就像用户第一次打开应用程序时,它会做以下操作
因为当前数据库是空的,所以它将空结果发送给隐藏进度条的观察者。当服务器将数据转储到数据库时,我想丢弃该事件并将结果发送给观察者。甚至服务器结果为空。因此,一旦确认不存在数据,进度条应始终隐藏。
换句话说,应用程序应该始终依赖于数据库,但如果它为空,那么它应该等到服务器响应,然后通知观察者。
这是我的代码
观察者
viewmodel.characters.observe(viewLifecycleOwner,Observer {
Log.e("status is ","${it.message} at ${System.currentTimeMillis()}")
when (it.status) {
Resource.Status.SUCCESS -> {
binding.progressBar.visibility = View.GONE
if (!it.data.isNullOrEmpty()) adapter.setItems(ArrayList(it.data))
}
Resource.Status.ERROR -> {
Toast.makeText(requireContext(),it.message,Toast.LENGTH_SHORT).show()
binding.progressBar.visibility = View.GONE
}
Resource.Status.LOADING ->
binding.progressBar.visibility = View.VISIBLE
}
})
视图模型
@Hiltviewmodel
class Charactersviewmodel @Inject constructor(
private val repository: CharacterRepository
) : viewmodel() {
val characters = repository.getCharacters()
}
存储库
class CharacterRepository @Inject constructor(
private val remoteDataSource: CharacterRemoteDataSource,private val localDataSource: CharacterDao
) {
fun getCharacters() : LiveData<Resource<List<Character>>> {
return performGetoperation(
databaseQuery = { localDataSource.getAllCharacters() },networkCall = { remoteDataSource.getCharacters() },saveCallResult = { localDataSource.insertAll(it.results) }
)
}
}
fun <T,A> performGetoperation(databaseQuery: () -> LiveData<T>,countQuery: () -> Int,networkCall: suspend () -> Resource<A>,saveCallResult: suspend (A) -> Unit): LiveData<Resource<T>> =
liveData(dispatchers.IO) {
emit(Resource.loading())
val source = databaseQuery().map { Resource.success(it,"database") }.distinctUntilChanged()
emitSource(source)
val responseStatus = networkCall()
if (responseStatus.status == SUCCESS) {
saveCallResult(responseStatus.data!!)
} else if (responseStatus.status == ERROR) {
emit(Resource.error(responseStatus.message!!))
}
}
本地数据源
@Dao
interface CharacterDao {
@Query("SELECT * FROM characters")
fun getAllCharacters() : LiveData<List<Character>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(characters: List<Character>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(character: Character)
}
数据源
class CharacterRemoteDataSource @Inject constructor(
private val characterService: CharacterService
): BaseDataSource() {
suspend fun getCharacters() = getResult { characterService.getAllCharacters() }}
}
基础数据源
abstract class BaseDataSource {
protected suspend fun <T> getResult(call: suspend () -> Response<T>): Resource<T> {
try {
Log.e("status is","started")
val response = call()
if (response.isSuccessful) {
val body = response.body()
if (body != null) return Resource.success(body,"server")
}
return error(" ${response.code()} ${response.message()}")
} catch (e: Exception) {
return error(e.message ?: e.toString())
}
}
private fun <T> error(message: String): Resource<T> {
Timber.d(message)
return Resource.error("Network call has Failed for a following reason: $message")
}
}
人物服务
interface CharacterService {
@GET("character")
suspend fun getAllCharacters() : Response<CharacterList>
}
资源
data class Resource<out T>(val status: Status,val data: T?,val message: String?) {
enum class Status {
SUCCESS,ERROR,LOADING
}
companion object {
fun <T> success(data: T,message : String): Resource<T> {
return Resource(Status.SUCCESS,data,message)
}
fun <T> error(message: String,data: T? = null): Resource<T> {
return Resource(Status.ERROR,message)
}
fun <T> loading(data: T? = null): Resource<T> {
return Resource(Status.LOADING,"loading")
}
}
}
字符列表
data class CharacterList(
val info: Info,val results: List<Character>
)
如果数据库为空,我忽略数据库并等待服务器响应然后通知观察者的最佳方法是什么
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。