如何通过 ViewModel 从 Fragment 观察 Repository LiveData
How to observe Repository LiveData from Fragment via ViewModel
我很难弄清楚如何在 @GET
请求的情况下连接我的 Repository
和 ViewModel
的实时数据并在片段中观察它们。
当请求类型为 @POST
时,我没有这个问题,因为我可以在正文上使用 Transformation.switchMap
并且每当正文更改时,存储库的函数都会被调用并实时向响应发出值数据是这样的
val matchSetsDetail: LiveData<Resource<MatchDetailBean>> = Transformations.switchMap(matchIdLiveData) { matchId ->
val body = MatchSetRequest(matchId)
repository.getMatchSet(body)
}
但是在 @GET
请求的情况下,我的视图提供了几个查询参数
我在存储库 class 中调用了此改造 API,代码如下所示
class Repository {
fun checkInCheckOutUser(apiKey: String, userId: Int, status: String, latitude: Double, longitude: Double, checkedOn: Long): LiveData<Resource<BaseResponse>> = liveData {
emit(Resource.Loading())
try {
val response: Response<BaseResponse> = ApiClient.coachApi.checkInCheckOutUser(apiKey, userId, status, latitude, longitude, checkedOn)
if (response.isSuccessful && response.body() != null) {
if (response.body()!!.isValidKey && response.body()!!.success) {
emit(Resource.Success(response.body()!!))
} else {
emit(Resource.Failure(response.body()!!.message))
}
} else {
emit(Resource.Failure())
}
} catch (e: Exception) {
emit(Resource.Failure())
}
}
}
和ViewModel
class CheckInMapViewModel : ViewModel() {
val checkInResponse: LiveData<Resource<BaseResponse>> = MutableLiveData()
fun checkInCheckOut(apiKey: String, userId: Int, status: String, latitude: Double, longitude: Double, checkedOn: Long): LiveData<Resource<BaseResponse>> {
return repository.checkInCheckOutUser(apiKey,userId,status,latitude,longitude,checkedOn)
}
}
主要问题是我想观察 checkInResponse
的方式与我观察 @POST
请求的方式相同,但不知道如何传递观察存储库 LiveData,就像我对 post 上面的请求使用 Transformations.switchMap
。谁能帮我处理这个案子?
编辑 - 这是我的改造服务 class 按要求
interface CoachApi {
@POST(Urls.CHECK_IN_CHECK_OUT_URL)
suspend fun checkInCheckOutUser(
@Query("apiKey") apiKey: String,
@Query("userId") userId: Int,
@Query("status") status: String,
@Query("latitude") latitude: Double,
@Query("longitude") longitude: Double,
@Query("checkedOn") checkedOn: Long
): Response<SelfCheckResponse>
@POST(Urls.SELF_CHECK_STATUS)
suspend fun getCheckInStatus(
@Query("apiKey") apiKey: String,
@Query("userId") userId: Int
): Response<SelfCheckStatusResponse>
}
试试这个:
class CheckInMapViewModel : ViewModel() {
private val _checkInResponse: MediatorLiveData<Resource<BaseResponse>> = MediatorLiveData()
val checkInResponse: LiveData<Resource<BaseResponse>>
get() = _checkInResponse
init {
_checkInResponse.addSource(checkInCheckOut()) {
_checkInResponse.value = it
}
}
fun checkInCheckOut(apiKey: String, userId: Int, status: String, latitude: Double, longitude: Double, checkedOn: Long): LiveData<Resource<BaseResponse>> {
return repository.checkInCheckOutUser(apiKey,userId,status,latitude,longitude,checkedOn)
}
}
您想要的方法可以使用中间 LiveData
来保存请求参数,名为 queryLiveData
。当 checkInCheckOut
函数被调用时,我们为它设置一个新值,导致 checkInResponse
发生变化。然后变化将转化为repository.checkInCheckOutUser
的结果使用switchMap
.
CheckInMapViewModel:
class CheckInMapViewModel : ViewModel() {
private val queryLiveData = MutableLiveData<CheckInCheckOutParam?>()
init {
queryLiveData.postValue(null)
}
val checkInResponse: LiveData<Resource<BaseResponse>> =
queryLiveData.switchMap { query ->
if(query == null) {
AbsentLiveData.create()
} else {
repository.checkInCheckOutUser(
query.apiKey,
query.userId,
query.status,
query.latitude,
query.longitude,
query.checkedOn
)
}
}
fun checkInCheckOut(
apiKey: String,
userId: Int,
status: String,
latitude: Double,
longitude: Double,
checkedOn: Long
) {
queryLiveData.postValue(
CheckInCheckOutParam(apiKey, userId, status, latitude, longitude, checkedOn)
)
}
private data class CheckInCheckOutParam(
val apiKey: String,
val userId: Int,
val status: String,
val latitude: Double,
val longitude: Double,
val checkedOn: Long
)
}
AbsentLiveData:
/**
* A LiveData class that has `null` value.
*/
class AbsentLiveData<T : Any?> private constructor(resource: Resource<T>) :
LiveData<Resource<T>>() {
init {
// use post instead of set since this can be created on any thread
postValue(resource)
}
companion object {
fun <T> create(): LiveData<Resource<T>> {
return AbsentLiveData(Resource.empty())
}
}
}
Transformations.switchMap()
只是利用MediatorLiveData
。由于您的用例有点不同,您可以直接自己实现它。
class CheckInMapViewModel : ViewModel() {
private val _checkInResponse = MediatorLiveData<Resource<BaseResponse>>
val checkInResponse: LiveData<Resource<BaseResponse>> = _checkInResponse
fun checkInCheckOut(apiKey: String, userId: Int, status: String, latitude: Double, longitude: Double, checkedOn: Long) {
val data = repository.checkInCheckOutUser(apiKey,userId,status,latitude,longitude,checkedOn)
_checkInResponse.addSource(data) {
if (it is Resource.Success || it is Resource.Failure)
_checkInResponse.removeSource(data)
_checkInResponse.value = it
}
}
}
此代码假设 data
仅发出一个终端元素 Resource.Success
或 Resource.Failure
并用它清理源。
我很难弄清楚如何在 @GET
请求的情况下连接我的 Repository
和 ViewModel
的实时数据并在片段中观察它们。
当请求类型为 @POST
时,我没有这个问题,因为我可以在正文上使用 Transformation.switchMap
并且每当正文更改时,存储库的函数都会被调用并实时向响应发出值数据是这样的
val matchSetsDetail: LiveData<Resource<MatchDetailBean>> = Transformations.switchMap(matchIdLiveData) { matchId ->
val body = MatchSetRequest(matchId)
repository.getMatchSet(body)
}
但是在 @GET
请求的情况下,我的视图提供了几个查询参数
我在存储库 class 中调用了此改造 API,代码如下所示
class Repository {
fun checkInCheckOutUser(apiKey: String, userId: Int, status: String, latitude: Double, longitude: Double, checkedOn: Long): LiveData<Resource<BaseResponse>> = liveData {
emit(Resource.Loading())
try {
val response: Response<BaseResponse> = ApiClient.coachApi.checkInCheckOutUser(apiKey, userId, status, latitude, longitude, checkedOn)
if (response.isSuccessful && response.body() != null) {
if (response.body()!!.isValidKey && response.body()!!.success) {
emit(Resource.Success(response.body()!!))
} else {
emit(Resource.Failure(response.body()!!.message))
}
} else {
emit(Resource.Failure())
}
} catch (e: Exception) {
emit(Resource.Failure())
}
}
}
和ViewModel
class CheckInMapViewModel : ViewModel() {
val checkInResponse: LiveData<Resource<BaseResponse>> = MutableLiveData()
fun checkInCheckOut(apiKey: String, userId: Int, status: String, latitude: Double, longitude: Double, checkedOn: Long): LiveData<Resource<BaseResponse>> {
return repository.checkInCheckOutUser(apiKey,userId,status,latitude,longitude,checkedOn)
}
}
主要问题是我想观察 checkInResponse
的方式与我观察 @POST
请求的方式相同,但不知道如何传递观察存储库 LiveData,就像我对 post 上面的请求使用 Transformations.switchMap
。谁能帮我处理这个案子?
编辑 - 这是我的改造服务 class 按要求
interface CoachApi {
@POST(Urls.CHECK_IN_CHECK_OUT_URL)
suspend fun checkInCheckOutUser(
@Query("apiKey") apiKey: String,
@Query("userId") userId: Int,
@Query("status") status: String,
@Query("latitude") latitude: Double,
@Query("longitude") longitude: Double,
@Query("checkedOn") checkedOn: Long
): Response<SelfCheckResponse>
@POST(Urls.SELF_CHECK_STATUS)
suspend fun getCheckInStatus(
@Query("apiKey") apiKey: String,
@Query("userId") userId: Int
): Response<SelfCheckStatusResponse>
}
试试这个:
class CheckInMapViewModel : ViewModel() {
private val _checkInResponse: MediatorLiveData<Resource<BaseResponse>> = MediatorLiveData()
val checkInResponse: LiveData<Resource<BaseResponse>>
get() = _checkInResponse
init {
_checkInResponse.addSource(checkInCheckOut()) {
_checkInResponse.value = it
}
}
fun checkInCheckOut(apiKey: String, userId: Int, status: String, latitude: Double, longitude: Double, checkedOn: Long): LiveData<Resource<BaseResponse>> {
return repository.checkInCheckOutUser(apiKey,userId,status,latitude,longitude,checkedOn)
}
}
您想要的方法可以使用中间 LiveData
来保存请求参数,名为 queryLiveData
。当 checkInCheckOut
函数被调用时,我们为它设置一个新值,导致 checkInResponse
发生变化。然后变化将转化为repository.checkInCheckOutUser
的结果使用switchMap
.
CheckInMapViewModel:
class CheckInMapViewModel : ViewModel() {
private val queryLiveData = MutableLiveData<CheckInCheckOutParam?>()
init {
queryLiveData.postValue(null)
}
val checkInResponse: LiveData<Resource<BaseResponse>> =
queryLiveData.switchMap { query ->
if(query == null) {
AbsentLiveData.create()
} else {
repository.checkInCheckOutUser(
query.apiKey,
query.userId,
query.status,
query.latitude,
query.longitude,
query.checkedOn
)
}
}
fun checkInCheckOut(
apiKey: String,
userId: Int,
status: String,
latitude: Double,
longitude: Double,
checkedOn: Long
) {
queryLiveData.postValue(
CheckInCheckOutParam(apiKey, userId, status, latitude, longitude, checkedOn)
)
}
private data class CheckInCheckOutParam(
val apiKey: String,
val userId: Int,
val status: String,
val latitude: Double,
val longitude: Double,
val checkedOn: Long
)
}
AbsentLiveData:
/**
* A LiveData class that has `null` value.
*/
class AbsentLiveData<T : Any?> private constructor(resource: Resource<T>) :
LiveData<Resource<T>>() {
init {
// use post instead of set since this can be created on any thread
postValue(resource)
}
companion object {
fun <T> create(): LiveData<Resource<T>> {
return AbsentLiveData(Resource.empty())
}
}
}
Transformations.switchMap()
只是利用MediatorLiveData
。由于您的用例有点不同,您可以直接自己实现它。
class CheckInMapViewModel : ViewModel() {
private val _checkInResponse = MediatorLiveData<Resource<BaseResponse>>
val checkInResponse: LiveData<Resource<BaseResponse>> = _checkInResponse
fun checkInCheckOut(apiKey: String, userId: Int, status: String, latitude: Double, longitude: Double, checkedOn: Long) {
val data = repository.checkInCheckOutUser(apiKey,userId,status,latitude,longitude,checkedOn)
_checkInResponse.addSource(data) {
if (it is Resource.Success || it is Resource.Failure)
_checkInResponse.removeSource(data)
_checkInResponse.value = it
}
}
}
此代码假设 data
仅发出一个终端元素 Resource.Success
或 Resource.Failure
并用它清理源。