如何在模型中设置数据?
How to set data in Model?
我有一个具有 [id;name;thumb] 的实体“饮料”,我正在使用这些实体进行 2 次响应调用。一个响应 returns 给我一个非酒精饮料清单,另一个 AlcoholList,我正在使用 Room 来缓存数据。但是当我 运行 应用程序时,我看到我的列表合并了,经过一番思考,我找到了解决这个问题的方法,我向我的实体“alcoholStatus”添加了一个布尔字段。但我不明白如何使用此 AccessDataStrategy 将数据正确设置到此变量中。我是 Android 的新手,这是我的学习项目。请给我解决这个问题的正确方法。
https://github.com/YaroslavSulyma/LetsDrink/tree/master/app/src/main/java/com/example/letsdrink
非常感谢!
实体
@Entity(tableName = "drinks")
data class DrinksModel(
@SerializedName("strDrink")
val strDrink: String,
@SerializedName("strDrinkThumb")
val strDrinkThumb: String?,
@SerializedName("idDrink")
@PrimaryKey
val idDrink: Int,
var alcohol: Boolean
)
DataAccessStrategyCode
fun <T, A> performGetOperation(
databaseQuery: () -> LiveData<T>,
networkCall: suspend () -> Resource<A>,
saveCallResult: suspend (A) -> Unit
): LiveData<Resource<T>> =
liveData(Dispatchers.IO) {
emit(Resource.loading())
val source = databaseQuery.invoke().map { Resource.success(it) }
emitSource(source)
val responseStatus = networkCall.invoke()
if (responseStatus.status == SUCCESS) {
saveCallResult(responseStatus.data!!)
} else if (responseStatus.status == ERROR) {
emit(Resource.error(responseStatus.message!!))
emitSource(source)
}
}
资源
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): Resource<T> {
return Resource(Status.SUCCESS, data, null)
}
fun <T> error(message: String, data: T? = null): Resource<T> {
return Resource(Status.ERROR, data, message)
}
fun <T> loading(data: T? = null): Resource<T> {
return Resource(Status.LOADING, data, null)
}
}
}
存储库
class CocktailsRepository @Inject constructor(
private val remoteDataSource: CocktailsRemoteDataSource,
private val localDataSource: CocktailsDao
) {
fun getAlcoholicCocktails() = performGetOperation(
databaseQuery = { localDataSource.getAlcoholicCocktails() },
networkCall = { remoteDataSource.getAllAlcoholicCocktails()},
saveCallResult = { localDataSource.insertAllDrinks(it.drinks) }
)
fun getNonAlcoholicCocktails() = performGetOperation(
databaseQuery = { localDataSource.getNonAlcoholicCocktails() },
networkCall = { remoteDataSource.getAllNonAlcoholicCocktails() },
saveCallResult = { localDataSource.insertAllDrinks(it.drinks) }
)
}
DAO
@Dao
interface CocktailsDao {
@Query("SELECT * FROM drinks WHERE alcohol = 'true'")
fun getAlcoholicCocktails(): LiveData<List<DrinksModel>>
@Query("SELECT * FROM drinks WHERE alcohol = 'false'")
fun getNonAlcoholicCocktails(): LiveData<List<DrinksModel>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAllDrinks(drinks: List<DrinksModel>)
}
远程数据源
class CocktailsRemoteDataSource @Inject constructor(private val iCocktailApisService: ICocktailApisService) :
BaseDataSource() {
suspend fun getAllAlcoholicCocktails() =
getResult { iCocktailApisService.allAlcoholicAndNonAlcoholicCocktails("Alcoholic") }
suspend fun getAllNonAlcoholicCocktails() =
getResult { iCocktailApisService.allAlcoholicAndNonAlcoholicCocktails("Non_Alcoholic") }
}
首先:我强烈建议您为远程和本地模型类定义单独的数据类,并在需要时在它们之间进行映射,例如:
远程数据模型:
data class DrinkRemoteModel(
@SerializedName("idDrink")
val idDrink: Int,
@SerializedName("strDrink")
val strDrink: String,
@SerializedName("strDrinkThumb")
val strDrinkThumb: String?,
@SerializedName("alcohol")
var alcohol: Boolean
)
本地数据模型:
@Entity(tableName = "drinks")
data class DrinkLocalModel(
@PrimaryKey
@ColumnInfo(name = "idDrink")
val idDrink: Int,
@ColumnInfo(name = "strDrink")
val strDrink: String,
@ColumnInfo(name = "strDrinkThumb")
val strDrinkThumb: String?,
@ColumnInfo(name = "alcohol")
var alcohol: Boolean
)
回到您的实现:我认为导致问题的原因是 Room 将实体中的布尔字段映射到整数列, 1
对应 true
,0
对应 false
,因此请尝试在您的 DAO 中更改您的查询,如下所示:
@Dao
interface CocktailsDao {
@Query("SELECT * FROM drinks WHERE alcohol = 1")
fun getAlcoholicCocktails(): LiveData<List<DrinksModel>>
@Query("SELECT * FROM drinks WHERE alcohol = 0")
fun getNonAlcoholicCocktails(): LiveData<List<DrinksModel>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAllDrinks(drinks: List<DrinksModel>)
}
或者: 你可以用一个 DAO 函数替换你的 getAlcoholicCocktails
和 getNonAlcoholicCocktails
,像这样:
@Query("SELECT * FROM drinks WHERE alcohol = :isAlcoholic")
fun getCocktails(isAlcoholic : Boolean = true): LiveData<List<DrinksModel>>
我有一个具有 [id;name;thumb] 的实体“饮料”,我正在使用这些实体进行 2 次响应调用。一个响应 returns 给我一个非酒精饮料清单,另一个 AlcoholList,我正在使用 Room 来缓存数据。但是当我 运行 应用程序时,我看到我的列表合并了,经过一番思考,我找到了解决这个问题的方法,我向我的实体“alcoholStatus”添加了一个布尔字段。但我不明白如何使用此 AccessDataStrategy 将数据正确设置到此变量中。我是 Android 的新手,这是我的学习项目。请给我解决这个问题的正确方法。
https://github.com/YaroslavSulyma/LetsDrink/tree/master/app/src/main/java/com/example/letsdrink
非常感谢!
实体
@Entity(tableName = "drinks")
data class DrinksModel(
@SerializedName("strDrink")
val strDrink: String,
@SerializedName("strDrinkThumb")
val strDrinkThumb: String?,
@SerializedName("idDrink")
@PrimaryKey
val idDrink: Int,
var alcohol: Boolean
)
DataAccessStrategyCode
fun <T, A> performGetOperation(
databaseQuery: () -> LiveData<T>,
networkCall: suspend () -> Resource<A>,
saveCallResult: suspend (A) -> Unit
): LiveData<Resource<T>> =
liveData(Dispatchers.IO) {
emit(Resource.loading())
val source = databaseQuery.invoke().map { Resource.success(it) }
emitSource(source)
val responseStatus = networkCall.invoke()
if (responseStatus.status == SUCCESS) {
saveCallResult(responseStatus.data!!)
} else if (responseStatus.status == ERROR) {
emit(Resource.error(responseStatus.message!!))
emitSource(source)
}
}
资源
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): Resource<T> {
return Resource(Status.SUCCESS, data, null)
}
fun <T> error(message: String, data: T? = null): Resource<T> {
return Resource(Status.ERROR, data, message)
}
fun <T> loading(data: T? = null): Resource<T> {
return Resource(Status.LOADING, data, null)
}
}
}
存储库
class CocktailsRepository @Inject constructor(
private val remoteDataSource: CocktailsRemoteDataSource,
private val localDataSource: CocktailsDao
) {
fun getAlcoholicCocktails() = performGetOperation(
databaseQuery = { localDataSource.getAlcoholicCocktails() },
networkCall = { remoteDataSource.getAllAlcoholicCocktails()},
saveCallResult = { localDataSource.insertAllDrinks(it.drinks) }
)
fun getNonAlcoholicCocktails() = performGetOperation(
databaseQuery = { localDataSource.getNonAlcoholicCocktails() },
networkCall = { remoteDataSource.getAllNonAlcoholicCocktails() },
saveCallResult = { localDataSource.insertAllDrinks(it.drinks) }
)
}
DAO
@Dao
interface CocktailsDao {
@Query("SELECT * FROM drinks WHERE alcohol = 'true'")
fun getAlcoholicCocktails(): LiveData<List<DrinksModel>>
@Query("SELECT * FROM drinks WHERE alcohol = 'false'")
fun getNonAlcoholicCocktails(): LiveData<List<DrinksModel>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAllDrinks(drinks: List<DrinksModel>)
}
远程数据源
class CocktailsRemoteDataSource @Inject constructor(private val iCocktailApisService: ICocktailApisService) :
BaseDataSource() {
suspend fun getAllAlcoholicCocktails() =
getResult { iCocktailApisService.allAlcoholicAndNonAlcoholicCocktails("Alcoholic") }
suspend fun getAllNonAlcoholicCocktails() =
getResult { iCocktailApisService.allAlcoholicAndNonAlcoholicCocktails("Non_Alcoholic") }
}
首先:我强烈建议您为远程和本地模型类定义单独的数据类,并在需要时在它们之间进行映射,例如:
远程数据模型:
data class DrinkRemoteModel(
@SerializedName("idDrink")
val idDrink: Int,
@SerializedName("strDrink")
val strDrink: String,
@SerializedName("strDrinkThumb")
val strDrinkThumb: String?,
@SerializedName("alcohol")
var alcohol: Boolean
)
本地数据模型:
@Entity(tableName = "drinks")
data class DrinkLocalModel(
@PrimaryKey
@ColumnInfo(name = "idDrink")
val idDrink: Int,
@ColumnInfo(name = "strDrink")
val strDrink: String,
@ColumnInfo(name = "strDrinkThumb")
val strDrinkThumb: String?,
@ColumnInfo(name = "alcohol")
var alcohol: Boolean
)
回到您的实现:我认为导致问题的原因是 Room 将实体中的布尔字段映射到整数列, 1
对应 true
,0
对应 false
,因此请尝试在您的 DAO 中更改您的查询,如下所示:
@Dao
interface CocktailsDao {
@Query("SELECT * FROM drinks WHERE alcohol = 1")
fun getAlcoholicCocktails(): LiveData<List<DrinksModel>>
@Query("SELECT * FROM drinks WHERE alcohol = 0")
fun getNonAlcoholicCocktails(): LiveData<List<DrinksModel>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAllDrinks(drinks: List<DrinksModel>)
}
或者: 你可以用一个 DAO 函数替换你的 getAlcoholicCocktails
和 getNonAlcoholicCocktails
,像这样:
@Query("SELECT * FROM drinks WHERE alcohol = :isAlcoholic")
fun getCocktails(isAlcoholic : Boolean = true): LiveData<List<DrinksModel>>