微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何第一次忽略空数据库结果并在应用程序中等待服务器结果?

如何解决如何第一次忽略空数据库结果并在应用程序中等待服务器结果?

我的应用程序使用房间作为数据库并改造为网络调用 api。 我仅将数据库视为单一的事实来源。一切正常。但我没有找到一种情况的解决方案。 就像用户第一次打开应用程序时,它会做以下操作

  1. 数据库获取数据
  2. 从服务器获取数据

因为当前数据库是空的,所以它将空结果发送给隐藏进度条的观察者。当服务器将数据转储到数据库时,我想丢弃该事件并将结果发送给观察者。甚至服务器结果为空。因此,一旦确认不存在数据,进度条应始终隐藏。

换句话说,应用程序应该始终依赖于数据库,但如果它为空,那么它应该等到服务器响应,然后通知观察者。

这是我的代码

观察者

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) }
        )
    }
}

用于所有 api 和数据库处理的实用函数

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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?