I am having a hard time figuring out how I can connect my Repository
and ViewModel
's live data in-case of @GET
request and observe them in the fragment.
I don't have this problem when the request type is @POST
because I can use Transformation.switchMap
on the body and whenever the body changes repository's function gets invoked and emits value to the response live data something like this
val matchSetsDetail: LiveData<Resource<MatchDetailBean>> = Transformations.switchMap(matchIdLiveData) { matchId ->
val body = MatchSetRequest(matchId)
repository.getMatchSet(body)
}
but in case of @GET
request, I have several query parameter that my View supplies
I have this retrofit API call in repository class and the code looks like this
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())
}
}
}
and 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)
}
}
The main problem is I want to observe checkInResponse
the same way I am observing in case of @POST
request but don't know how to pass observe repository LiveData as I did with my post request above using Transformations.switchMap
. Can anyone help me with this case?
Edit - Here is my retrofit service class as asked
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>
}
The Transformations.switchMap()
just utilizes MediatorLiveData
. Since your use-case is a bit different, you could just directly implement it yourself.
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
}
}
}
This code is assuming that data
only emits one terminal element Resource.Success
or Resource.Failure
and cleans up the source with it.
Your desirable approach is possible using an intermediate LiveData
which holds the request params, named queryLiveData
. When the checkInCheckOut
function is called, we set a new value for it that causes a change in checkInResponse
. Then the change will be transformed into the result of repository.checkInCheckOutUser
using 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())
}
}
}
Try this:
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)
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.