Как наблюдать репозиторий LiveData из фрагмента через ViewModel - PullRequest
1 голос
/ 31 октября 2019

Мне трудно понять, как я могу подключить свои Repository и ViewModel данные в реальном времени в случае запроса @GET и наблюдать их во фрагменте.

Я не понимаюУ меня нет этой проблемы, когда тип запроса @POST, потому что я могу использовать Transformation.switchMap в теле, и всякий раз, когда тело меняет тело, вызывается функция репозитория, которая выдает значение в живые данные ответа, что-то вроде этого

val matchSetsDetail: LiveData<Resource<MatchDetailBean>> = Transformations.switchMap(matchIdLiveData) { matchId ->
        val body = MatchSetRequest(matchId)
        repository.getMatchSet(body)
    }

, но в случае запроса @GET у меня есть несколько параметров запроса, которые мой View предоставляет

У меня есть этот вызов модифицированного 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 хранилища, как ясделал с моим запросом выше, используя Transformations.switchMap. Может ли кто-нибудь помочь мне с этим делом?

Редактировать - Вот мой класс обслуживания, как меня спросили

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>
}

Ответы [ 3 ]

3 голосов
/ 09 ноября 2019

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 и очищаетисточник с ним.

1 голос
/ 07 ноября 2019

Ваш желательный подход возможен при использовании промежуточного элемента 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())
        }
    }
}
0 голосов
/ 31 октября 2019

Попробуйте это:

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)
    }
}
...