1

The problem is I could not get the response using LiveData and Courotine in the viewModel. Possibly I do not know the right way to do that. The call is

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

The repository is

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

What I am trying to do in viewmodel is,

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

And its not working. Could you please tell me what I am doing wrong? Thanks

sadat
  • 4,004
  • 2
  • 29
  • 49

2 Answers2

1

It seems to me that the reason why you are not getting the result is because there are no Observers for the LiveData returned by authRepository.login(username, password)

You need to do something like:

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

This usually happens inside a Fragment or Activity which are LifeCyclerOwners.

Also, liveData {...} takes a suspend block, but it is not itself a suspend function. This means that login() does not need to be a suspend function.

Emmanuel
  • 13,083
  • 4
  • 39
  • 53
  • Thats the problem. the login function in ViewModel has two arguments. how can I make result variable available in Fragment or Activity. – sadat Feb 08 '20 at 10:47
  • Make `result` an instance variable and assign `authRepository.login(username, password)` to it. Then call `.observe()` on it from the `Fragment`. – Emmanuel Feb 08 '20 at 15:55
  • In that case, how do I pass the username and password to invoke the call. – sadat Feb 10 '20 at 01:22
  • could you please guide me how can I invoke the call, if I keep result = authRepository.login(username, password) in viewmodel. – sadat Feb 10 '20 at 08:15
  • You can make `result` a method in the view model that takes in username and password. – Emmanuel Feb 10 '20 at 15:51
  • If its a method then how do I observe that method from view? – sadat Feb 10 '20 at 22:53
  • By calling `.observe()` on the method? From the `Fragment` it would be `viewModel.login(username, password).observe(...)` – Emmanuel Feb 11 '20 at 13:24
  • @Emmanuel i need your help here --> https://stackoverflow.com/questions/64352752/user-login-using-viewmodel-and-retrofit – android dev Oct 14 '20 at 12:09
0

Check below code for architecture using MVVM + Koin [ https://github.com/parthpatibandha/MvvmCleanKotlin ]

Retrofit interface

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

Repository

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

Hope it helps you for understand MVVM with Koin.