Android 安卓机房:离线缓存不';行不通
我遵循了尝试在我的应用程序中实现在线缓存的过程。虽然一切看起来都很相似,但当我打开飞行模式时,数据并没有显示出来。这是我的密码: 存储库Android 安卓机房:离线缓存不';行不通,android,kotlin,repository,android-room,Android,Kotlin,Repository,Android Room,我遵循了尝试在我的应用程序中实现在线缓存的过程。虽然一切看起来都很相似,但当我打开飞行模式时,数据并没有显示出来。这是我的密码: 存储库 class WeatherRepository(private val database: WeatherDatabase) { var weather: LiveData<CurrentWeather> = Transformations.map(database.weatherDao.getWeather()){ it
class WeatherRepository(private val database: WeatherDatabase) {
var weather: LiveData<CurrentWeather> = Transformations.map(database.weatherDao.getWeather()){
it.asDomainModel()
}
suspend fun refreshWeather(city: String){
withContext(Dispatchers.IO){
val weather = WeatherNetwork.service.getCurrentWeather("London", "metric")
database.weatherDao.insert(weather.asDatabaseModel())
Log.i("INSERTING: ", weather.asDatabaseModel().toString())
}
}
//I've created this function only for debugging
fun getDataFromDB(){
weather = Transformations.map(database.weatherDao.getWeather()){
it.asDomainModel()
}
val data = database.weatherDao.getWeather()
Log.i("DB VALUES: ", data.value.toString())
Log.i("VAR WEATHER IN REPO: ", weather.value.toString())
}
}
const val WEATHER_ID = 0
@Entity(tableName = "current_weather")
data class DatabaseWeather constructor(
val name: String,
val lon: Double,
val lat: Double,
val description: String,
val icon: String,
val temp: Double,
val tempFeelsLike: Double,
val humidity: Int,
val pressure: Int
){
@PrimaryKey(autoGenerate = false)
var id: Int = WEATHER_ID
}
fun DatabaseWeather.asDomainModel(): CurrentWeather{
return CurrentWeather(
name = this.name,
lon = this.lon,
lat = this.lat,
description = this.description,
icon = this.icon,
temp = this.temp,
tempFeelsLike = this.tempFeelsLike,
humidity = this.humidity,
pressure = this.pressure
)
}
网络
const val BASE_URL = "https://api.openweathermap.org/data/2.5/"
const val API_KEY = "xxx"
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
interface WeatherApiService {
@GET("weather")
suspend fun getCurrentWeather(
@Query("q") cityName: String,
@Query("units") units: String
): WeatherResponse
}
object WeatherNetwork{
private val requestInterceptor = Interceptor { chain ->
val url = chain.request()
.url()
.newBuilder()
.addQueryParameter("appid", API_KEY)
.build()
val request = chain.request()
.newBuilder()
.url(url)
.build()
return@Interceptor chain.proceed(request)
}
private val okHttpClient = OkHttpClient.Builder()
.addInterceptor(requestInterceptor)
.build()
private val retrofit = Retrofit.Builder()
.client(okHttpClient)
.baseUrl(BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
val service = retrofit.create(WeatherApiService::class.java)
}
视图模型
enum class WeatherApiStatus { LOADING, ERROR, DONE }
class CurrentWeatherViewModel(application: Application) : AndroidViewModel(application) {
val place = MutableLiveData<String>()
private val _status = MutableLiveData<WeatherApiStatus>()
val status: LiveData<WeatherApiStatus>
get() = _status
private val weatherRepository = WeatherRepository(getDatabase(application))
val weather = weatherRepository.weather
init {
refreshDataFromRepository()
}
fun refreshDataFromRepository(){
viewModelScope.launch {
try{
weatherRepository.refreshWeather(place.value.toString())
_status.value = WeatherApiStatus.DONE
} catch (e: Exception){
Log.i("FAILURE: ", e.printStackTrace().toString())
_status.value = WeatherApiStatus.ERROR
}
}
}
fun checkDB(){
weatherRepository.getDataFromDB()
}
}
enum类状态{正在加载,错误,完成}
类CurrentWeatherViewModel(应用程序:应用程序):AndroidViewModel(应用程序){
val place=MutableLiveData()
private val_status=MutableLiveData()
val状态:LiveData
获取()
私有val weatherRepository=weatherRepository(getDatabase(应用程序))
val weather=weatherRepository.weather
初始化{
refreshDataFromRepository()
}
fun refreshDataFromRepository(){
viewModelScope.launch{
试一试{
weatherRepository.refreshWeather(place.value.toString())
_status.value=WeatherApiStatus.DONE
}捕获(e:例外){
Log.i(“失败:”,例如printStackTrace().toString())
_status.value=WeatherApiStatus.ERROR
}
}
}
fun checkDB(){
weatherRepository.getDataFromDB()文件
}
}
当我不调用WeatherRepository中的refreshWeather方法(数据是从db下载的)时,它正在工作。
我不知道为什么,但是日志“DB VALUES”和“VAR WEATHER IN REPO”总是显示为空(“插入”正确显示数据)当您尝试记录从房间DB检索到的值时遇到的问题,它总是显示为空,这是因为数据库检索过程始终是异步进行的,并且在尝试记录数据时数据尚未准备就绪 正如您所看到的,DAO的
getWeather()
方法返回一个LiveData
,您在请求后立即尝试记录它的值,没有给足够的时间从磁盘获取它,因此导致仍然是null
值
由于此类操作的IO性质(与代码和变量所在的CPU和RAM内存的速度相比,磁盘访问速度非常慢),您应该观察此LiveData
,以便在成功从数据库检索到值时收到通知
仅用于调试目的(此代码会导致许多问题,例如性能和内存问题,因为它会一直监听LiveData
,建议使用observe
方法传递LifecycleOwner
,而不是一直观察),您可以这样做:
fun getDataFromDB(){
weather = Transformations.map(database.weatherDao.getWeather()){
it.asDomainModel()
}
val data = database.weatherDao.getWeather()
data.observeForever { value ->
Log.i("DB VALUES: ", value.toString())
}
weather.observeForever { value ->
Log.i("VAR WEATHER IN REPO: ", value.toString())
}
}
另一种实现方法是将DAO函数的返回类型更改为直接返回DatabaseWeather
,使其成为suspend fun
,如下所示:
suspend fun getWeather(): DatabaseWeather
但是,您需要更改一组其他代码,只需“等待”获取值并在记录之前准备就绪(就像在“插入”情况下,由于其中的“挂起”函数,代码在协同路由上等待WeatherNetwork
调用)
suspend fun getWeather(): DatabaseWeather