Как наблюдать данные во вьюмодели LiveData + Courotine + MVVM + Retrofit

Проблема в том, что я не мог получить ответ, используя LiveData и Courotine в viewModel. Возможно, я не знаю, как это сделать. Звонок

interface AuthApiService {
    @POST("v2/5e3cba6a2d00008709d958d0")
    @FormUrlEncoded
    suspend fun login(
        @Field("username") username: String,
        @Field("password") password: String
    ): Response<AuthToken>
}

Репозиторий

class AuthRepository
@Inject
constructor(
    val authApiService: AuthApiService
) {
    suspend fun login(username: String, password: String) = liveData {
        emit(GenericResult.Loading(null))
        try {
            emit(GenericResult.Success(authApiService.login(username, password)))
        } catch (ioException: Exception) {
            emit(GenericResult.Error(ioException))
        }
    }
}

Что я пытаюсь сделать в модели просмотра, так это

viewModelScope.launch {
            val result = authRepository.login(username, password)

            when (result.value) {
                is GenericResult.Loading -> isLoading.postValue(true)
                is GenericResult.Success -> authToken.postValue((result.value as GenericResult.Success<Response<AuthToken>>).data.body())
                is GenericResult.Error -> onMessageError.postValue((result.value as GenericResult.Error).exception)
            }
        }

И это не работает. Подскажите, пожалуйста, что я делаю не так? Спасибо


person sadat    schedule 07.02.2020    source источник
comment
Вы получаете какую-нибудь ошибку?   -  person Patibandha Parth    schedule 07.02.2020
comment
Ошибки нет. Я не получаю результата.   -  person sadat    schedule 07.02.2020


Ответы (2)


Мне кажется, что причина, по которой вы не получаете результат, заключается в том, что нет Observers для LiveData, возвращаемого authRepository.login(username, password)

Вам нужно сделать что-то вроде:

val result = authRepository.login(username, password)
result.observe(someLifeCycleOwner, Observer {...})

Обычно это происходит внутри Fragment или Activity, которые равны LifeCyclerOwners.

Кроме того, liveData {...} принимает блок suspend, но сам по себе не является suspend функцией. Это означает, что login() не обязательно должна быть suspend функцией.

person Emmanuel    schedule 07.02.2020
comment
Это проблема. функция входа в ViewModel имеет два аргумента. как сделать переменную результата доступной во фрагменте или действии. - person sadat; 08.02.2020
comment
Сделайте result переменной экземпляра и присвойте ей authRepository.login(username, password). Затем вызовите .observe() по нему из Fragment. - person Emmanuel; 08.02.2020
comment
В этом случае, как мне передать имя пользователя и пароль для вызова вызова. - person sadat; 10.02.2020
comment
не могли бы вы подсказать мне, как я могу вызвать вызов, если я сохраню result = authRepository.login (имя пользователя, пароль) в модели просмотра. - person sadat; 10.02.2020
comment
Вы можете сделать result методом в модели представления, который принимает имя пользователя и пароль. - person Emmanuel; 10.02.2020
comment
Если это метод, то как мне наблюдать за этим методом из поля зрения? - person sadat; 11.02.2020
comment
Вызов .observe() метода? Из Fragment было бы viewModel.login(username, password).observe(...) - person Emmanuel; 11.02.2020
comment
@Emmanuel, здесь мне нужна ваша помощь - ›stackoverflow.com/questions/64352752/ - person apj123; 14.10.2020

Проверьте приведенный ниже код для архитектуры с использованием MVVM + Koin [https://github.com/parthpatibandha/MvvmCleanKotlin]

Модернизация интерфейса

interface MovieApiService {
    @POST(ApiConstant.API_MOVIES)
    fun getAllMovieList(
        @Query("page") page : String
    ): Deferred<FlickerImageListRS>
}

Репозиторий

class HomeRepository constructor(
    private val homeLocalDataSource: HomeLocalDataSource,
    private val homeRemoteDataSource: HomeRemoteDataSource
) : BaseRepository(), HomeRepo {
    override suspend fun getAllMovieList(flickerImageListPRQ: FlickerImageListPRQ): Either<MyAppException, FlickerImageListRS> {
        return either(homeRemoteDataSource.getAllMovieList(flickerImageListPRQ))
    }
}

ViewModel

class MovieListingViewModel constructor(private val homeRepo: HomeRepo) : BaseViewModel() {

    val movieListRSLiveData: MutableLiveData<FlickerImageListRS> = MutableLiveData()
    fun getMovieList(page : String) {
        launch {
            postValue(homeRepo.getAllMovieList(FlickerImageListPRQ(page)), movieListRSLiveData)
        }
    }

Надеюсь, это поможет вам понять MVVM с Koin.

person Patibandha Parth    schedule 07.02.2020
comment
Спасибо за ответ. Зачем мне использовать Deferred. Ни в одном из новых образцов Google это больше не используется. - person sadat; 07.02.2020
comment
Да, с последней версией модернизации вы можете напрямую вернуть FlickerImageListRS. - person Patibandha Parth; 07.02.2020