简体   繁体   English

如何通过 ViewModel 从 Fragment 观察 Repository LiveData

[英]How to observe Repository LiveData from Fragment via ViewModel

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.我很难弄清楚如何在@GET请求的情况下连接我的RepositoryViewModel的实时数据并在片段中观察它们。

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当请求类型为@POST时我没有这个问题,因为我可以在主体上使用Transformation.switchMap并且每当主体更改存储库的 function 被调用并向响应实时数据发出值,如下所示

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但是在@GET请求的情况下,我的视图提供了几个查询参数

I have this retrofit API call in repository class and the code looks like this我在存储库 class 中有这个 retrofit 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())
            }
        }
}

and ViewModelViewModel

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 .主要问题是我想以与@POST请求相同的方式观察checkInResponse但不知道如何传递观察存储库 LiveData ,就像我使用Transformations.switchMap对上面的 post 请求所做的那样。 Can anyone help me with this case?谁能帮我处理这个案子?

Edit - Here is my retrofit service class as asked编辑 - 这是我的 retrofit 服务 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>
}

The Transformations.switchMap() just utilizes MediatorLiveData . Transformations.switchMap()仅使用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.此代码假设data仅发出一个终端元素Resource.SuccessResource.Failure并用它清理源。

Your desirable approach is possible using an intermediate LiveData which holds the request params, named queryLiveData .您可以使用包含请求参数的中间LiveData来实现您想要的方法,名为queryLiveData When the checkInCheckOut function is called, we set a new value for it that causes a change in checkInResponse .checkInCheckOut function 被调用时,我们为其设置了一个新值,导致checkInResponse发生变化。 Then the change will be transformed into the result of repository.checkInCheckOutUser using switchMap .然后使用switchMap将更改转换为repository.checkInCheckOutUser的结果。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM