Search code examples
androidkotlinmvvmviewmodel

UI is not updating while viewModel is updated in android kotlin


I am following the MVVM pattern Activity-->ViewModel ---> Repository . Repository is calling api and updated the LiveData. The value is of LiveData is also updated in ViewModel but its not reflecting on Activity. Please guide me where i am missing, Code is given below

Activity code:

class LoginWithEmailActivity : AppCompatActivity() {

    private var loginViewModel: LoginViewModel? = null
    private var binding: ActivityLoginWithEmailBinding? = null
    private var btnLogin : Button? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
       
        loginViewModel = ViewModelProviders.of(this).get(LoginViewModel::class.java)

        binding = DataBindingUtil.setContentView(this@LoginWithEmailActivity, R.layout.activity_login_with_email)
        binding!!.setLifecycleOwner(this)
        binding!!.setLoginViewModel(loginViewModel)
        btnLogin = findViewById(R.id.btn_login)

        loginViewModel!!.servicesLiveData!!.observe(this, Observer<LoginDataModel?> { serviceSetterGetter ->

            val msg = serviceSetterGetter.success
            Toast.makeText(this@LoginWithEmailActivity, ""+msg, Toast.LENGTH_SHORT).show()
            Log.v("///LOGIN SUCCESS////",""+msg);
           
        })
        btnLogin!!.setOnClickListener {
            loginViewModel!!.getUser()

        }
}

ViewModel.kt

class LoginViewModel : ViewModel() {
    var servicesLiveData: MutableLiveData<LoginDataModel>? = MutableLiveData()

    fun getUser() {
        servicesLiveData = MainActivityRepository.getServicesApiCall()
    }
}

Repository.kt

object MainActivityRepository {

    val serviceSetterGetter = MutableLiveData<LoginDataModel>()

    fun getServicesApiCall(): MutableLiveData<LoginDataModel> {
        val params = JsonObject()
        params.addProperty("email", "xyz@gmail.com")
        val call: Call<LoginDataModel> = ApiClient.getClient.getPhotos(params)

        call.enqueue(object : Callback<LoginDataModel> {

            @RequiresApi(Build.VERSION_CODES.N)
            override fun onResponse(call: Call<LoginDataModel>?, response: Response<LoginDataModel>?) {
                if (response != null) {
                    val data = response.body()
                    serviceSetterGetter?.postValue(data);
                   
                }
            }

            override fun onFailure(call: Call<LoginDataModel>?, t: Throwable?) {
            }

        })
        return serviceSetterGetter
    }
}

Solution

  • You subscribe to the LiveData in onCreate

    loginViewModel!!.servicesLiveData!!.observe(this, Observer<LoginDataModel?> { serviceSetterGetter ->
    
                val msg = serviceSetterGetter.success
                Toast.makeText(this@LoginWithEmailActivity, ""+msg, Toast.LENGTH_SHORT).show()
                Log.v("///LOGIN SUCCESS////",""+msg);
               
            })
    

    but then getUser creates a new reference

    fun getUser() {
        servicesLiveData = MainActivityRepository.getServicesApiCall()
    }
    

    The one you are subscribed to is not the same as the getUser liveData.

    If you want to keep what you have mostly the same you need to use MediatorLiveData

    Or just do

    getUser().observe(this, Observer<LoginDataModel?> { serviceSetterGetter ->
    
        val msg = serviceSetterGetter.success
        Toast.makeText(this@LoginWithEmailActivity, ""+msg, Toast.LENGTH_SHORT).show()
        Log.v("///LOGIN SUCCESS////",""+msg);
               
    })
    
    fun getUser(): LiveData<LoginDataModel> {
        return MainActivityRepository.getServicesApiCall()
    }