1

I am new to MVVVM and retrofit i have successfully implemented MVVM and is able to move data from retrofit to repository then Repository to ViewModel and view.

While doing this i came up to a massive confusion which is mentioned below. In first scenario my code looks like this:

Repository:

 fun iniateOTPprocess() : LiveData<GenericResponse> {


    RetroUtils.getApiManager().listRepos().enqueue(object : RetrofitCallback() {

        override fun onResponse(call: Call<GenericResponse>, response: Response<GenericResponse>) {
            super.onResponse(call, response)

            result.value = response.body()

        }
    }

    )

  return result
}

ViewModel:

 class LoginViewModel2(application: Application) : AndroidViewModel(application) {

lateinit var username: MutableLiveData<String>
lateinit var password: MutableLiveData<String>
var repository: LoginRepository = LoginRepository(application)
var data = MediatorLiveData<GenericResponse>()
var result = MutableLiveData<GenericResponse>()

init {
    data.addSource(result , Observer {
        data.postValue(it)
    })
}

fun onLoginBtnCLicked() {
    initiateOTP()
}

private fun initiateOTP() {
  result =  repository.iniateOTPprocess()
}

  fun getResponse() : MediatorLiveData<GenericResponse>{
   return data
  }
 }

The Mediator live data is never updated this way once the data is updated.

But if i change this code to

Repository

  class LoginRepository(var application: Application) {

var callback: RetrofitCallback = RetrofitCallback()
var result = MutableLiveData<GenericResponse>()

fun iniateOTPprocess() {

    RetroUtils.getApiManager().listRepos().enqueue(object : RetrofitCallback() {

        override fun onResponse(call: Call<GenericResponse>, response: Response<GenericResponse>) {
            super.onResponse(call, response)

            result.value = response.body()
        }
    }
    )
}

fun getData(): MutableLiveData<GenericResponse> {
    return result
}
}

ViewModel

class LoginViewModel2(application: Application) : AndroidViewModel(application) {

lateinit var username: MutableLiveData<String>
lateinit var password: MutableLiveData<String>
var repository: LoginRepository = LoginRepository(application)
var data = MediatorLiveData<GenericResponse>()
var result = MutableLiveData<GenericResponse>()

init {
    data.addSource(repository.getData(), Observer {
        data.postValue(it)
    })
}

fun onLoginBtnCLicked() {
    initiateOTP()
}

private fun initiateOTP() {
    repository.iniateOTPprocess()
}

 fun getResponse() : MediatorLiveData<GenericResponse>{

   return data
 }
}

This code starts working magically. In the view i am observing getResponse() method in both the scenarios. Can anyone here help with the confusion and can explain where the magic is happening. Thanks in advance.

Arnold Brown
  • 1,330
  • 13
  • 28
Harry Sharma
  • 2,190
  • 2
  • 15
  • 41
  • In your first scenario, are you calling `initiateOTP()` first before observing `getResponse()` ? – Christilyn Arjona Jan 10 '20 at 06:41
  • initiateOTP is called on button click whereas getResponse is observed at the time of instance creation in Activity – Harry Sharma Jan 10 '20 at 06:43
  • If you are new in MVVM and wants to learn MVVM, then here you can find sample application of MVVM implementation. MVVMCleanKotlin [ https://github.com/parthpatibandha/MvvmCleanKotlin ] Sample android application using Flickr images apis, Application using MVVM + Clean architecture + DI (Koin Dependency injection) – Patibandha Parth Jan 21 '20 at 07:03

2 Answers2

0

In your first scenario, even though you are updating result through this function:

private fun initiateOTP() {
  result =  repository.iniateOTPprocess()
}

You won't be able to observe the changes in this new result instance since you are already observing the first result instance created when you instantiate your ViewModel:

var result = MutableLiveData<GenericResponse>() // you are observing this instance
init {
    // this result never gets updated
    data.addSource(result , Observer {
        data.postValue(it)


    })

}

...

 fun getResponse() : MediatorLiveData<GenericResponse>{

    return data

 }
Christilyn Arjona
  • 2,173
  • 3
  • 13
  • 20
  • Can you please explain it more when you say "You won't be able to observe the changes since you are already observing the result instance created when you first instantiate your ViewModel" – Harry Sharma Jan 10 '20 at 06:57
  • @HarrySharma Sorry for the confusion. What I meant by that is even though you're re-assigning `result` in `initiateOTP()`, you are still observing the first instance of `result` from `var result = MutableLiveData()` because of your `init` function. Hope that helps – Christilyn Arjona Jan 10 '20 at 07:04
  • So in this case why it is working in second scenario in which in first instance the repository function getResponse() return the null value till API response is fetched.. – Harry Sharma Jan 10 '20 at 07:06
  • @HarrySharma because you're using only one `result` instance which gets updated in Repository. Also, in your second scenario, you can delete the `result` in `ViewModel` since you already have it in the `Repository` – Christilyn Arjona Jan 10 '20 at 07:09
  • So you mean i necessarily need to observe the first instance from repository rather than saving it in viewmodel and then observe it ?? – Harry Sharma Jan 10 '20 at 07:21
  • @HarrySharma Yes. When you create a `LiveData`, you shouldn't be re-assigning it in order to update its value. You should only have one instance of `LiveData` per use case. – Christilyn Arjona Jan 10 '20 at 07:23
  • 1
    Well thanks for the clarity dear.. I was in another world before this information :) – Harry Sharma Jan 10 '20 at 07:27
  • @HarrySharma Glad to help! – Christilyn Arjona Jan 10 '20 at 07:30
0

your code not following MVVM pattern every single live data must have observer, when you declare at init{} the value its not ready yet because its async. if you change to :

data.addSource(repository.iniateOTPprocess(), Observer {
        data.postValue(it)
})

the code will working,this is the best source to learn MVVM and livedata pattern google codelabs

Dony
  • 24
  • 6