onResume does not worked in viewmodel
Asked Answered
P

1

1

my data is fetched only when it is created...im using viewmodel...when press back button it doesnt update the previous data..onresume is not working in this...

i refered this but none of those helped--> Reacting to activity lifecycle in ViewModel

i need help

thanks in advance

activity:--

class MyAccount : BaseClassActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.myaccount)



    var mActionBarToolbar = findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbartable);
    setSupportActionBar(mActionBarToolbar);
  setEnabledTitle()


    val resetbutton=findViewById<Button>(R.id.resetpwd)
    resetbutton.setOnClickListener {
        val i=Intent(applicationContext,
            ResetPasswordActivity::class.java)
        startActivity(i)
    }
    val editbutton=findViewById<Button>(R.id.editdetail)
    editbutton.setOnClickListener {
        val i=Intent(applicationContext, EditProfile::class.java)
        startActivity(i)
    }

  hello()
}

override fun onResume() {
    super.onResume()
  hello()

}

fun hello(){
    val first_name = findViewById<TextView>(R.id.firstname)
    val last_name = findViewById<TextView>(R.id.lastname)
    val emailuser = findViewById<TextView>(R.id.emailuser)
    val phone_no = findViewById<TextView>(R.id.phone_no)
    val birthday = findViewById<TextView>(R.id.birthday)
    val image=findViewById<ImageView>(R.id.imageprofile)


    val model = ViewModelProvider(this)[MyAccountViewModel::class.java]

    model.viewmodel?.observe(this, object : Observer<My_account_base_response> {
        override fun onChanged(t: My_account_base_response?) {
            first_name.setText(t?.data?.user_data?.first_name)
            last_name.setText(t?.data?.user_data?.last_name)
            emailuser.setText(t?.data?.user_data?.email)
            phone_no.setText(t?.data?.user_data?.phone_no).toString()
            birthday.setText(t?.data?.user_data?.dob).toString()
            Glide.with(applicationContext).load(t?.data?.user_data?.profile_pic)
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .placeholder(R.drawable.ic_launcher_foreground)

                .into(image)
        }
    })


}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        android.R.id.home -> {
            NavUtils.navigateUpFromSameTask(this)

            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}}

viewmodel:--

class MyAccountViewModel(context: Application) :AndroidViewModel(context),LifecycleObserver{
private var MyAccountViewModels: MutableLiveData<My_account_base_response>? = null
val viewmodel: MutableLiveData<My_account_base_response>?
    get() {
        if (MyAccountViewModels == null) {
            MyAccountViewModels = MutableLiveData<My_account_base_response>()
            loadviewmodel()
        }
        return MyAccountViewModels

    }

private fun loadviewmodel(){
    val token :String = SharedPrefManager.getInstance(getApplication()).user.access_token.toString()
    RetrofitClient.instance.fetchUser(token)
        .enqueue(object : Callback<My_account_base_response> {
            override fun onFailure(call: Call<My_account_base_response>, t: Throwable) {

                Log.d("res", "" + t)


            }

            override fun onResponse(
                call: Call<My_account_base_response>,
                response: Response<My_account_base_response>
            ) {
                var res = response

                if (res.body()?.status == 200) {
                    MyAccountViewModels!!.value = response.body()

                } else {
                    try {
                        val jObjError =
                            JSONObject(response.errorBody()!!.string())
                        Toast.makeText(getApplication(),
                            jObjError.getString("user_msg"),
                            Toast.LENGTH_LONG).show()
                    } catch (e: Exception) {
                        Log.e("errorrr", e.message)
                    }
                }
            }
        })
}}
Pahari answered 15/10, 2020 at 12:43 Comment(2)
if (MyAccountViewModels == null) and then you MyAccountViewModels = MutableLiveData<My_account_base_response>() that means when on resume happens that will not be null and youst returns the else MyAccountViewModelsContraction
im returning return MyAccountViewModels @ContractionPahari
O
5

There are bunch of things wrong here, so let me provide you refactored code and explanation as much as I would be able to..

Activity:

class MyAccount : BaseClassActivity() {
    private val mActionBarToolbar by lazy { findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbartable) }
    private val resetbutton by lazy { findViewById<Button>(R.id.resetpwd) }
    private val editbutton by lazy { findViewById<Button>(R.id.editdetail) }
    private val first_name by lazy { findViewById<TextView>(R.id.firstname) }
    private val last_name by lazy { findViewById<TextView>(R.id.lastname) }
    private val emailuser by lazy { findViewById<TextView>(R.id.emailuser) }
    private val phone_no by lazy { findViewById<TextView>(R.id.phone_no) }
    private val birthday by lazy { findViewById<TextView>(R.id.birthday) }
    private val image by lazy { findViewById<ImageView>(R.id.imageprofile) }
    lateinit var model: MyAccountViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.myaccount)
        setSupportActionBar(mActionBarToolbar)
        setEnabledTitle()
        model = ViewModelProvider(this)[MyAccountViewModel::class.java]
        resetbutton.setOnClickListener {
            val i = Intent(applicationContext, ResetPasswordActivity::class.java)
            startActivity(i)
        }
        editbutton.setOnClickListener {
            val i = Intent(applicationContext, EditProfile::class.java)
            startActivity(i)
        }
        model.accountResponseData.observe(this, object : Observer<My_account_base_response> {
            override fun onChanged(t: My_account_base_response?) {
                first_name.setText(t?.data?.user_data?.first_name)
                last_name.setText(t?.data?.user_data?.last_name)
                emailuser.setText(t?.data?.user_data?.email)
                phone_no.setText(t?.data?.user_data?.phone_no).toString()
                birthday.setText(t?.data?.user_data?.dob).toString()
                Glide.with(applicationContext)
                    .load(t?.data?.user_data?.profile_pic)
                    .diskCacheStrategy(DiskCacheStrategy.ALL)
                    .placeholder(R.drawable.ic_launcher_foreground)
                    .into(image)
            }
        })
    }

    override fun onResume() {
        super.onResume()
        model.loadAccountData()
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            android.R.id.home -> {
                NavUtils.navigateUpFromSameTask(this)

                true
            }
            else -> super.onOptionsItemSelected(item)
        }
    }
}

Few notes on your activity class:

  1. You don't need to findViewById everytime, just do it once during onCreate or do it lazily. (FYI consider using kotlin synthetics or view binding or data binding)

  2. Initialize your viewModel during onCreate method only. (That's the best way to do it)

  3. Also observer your LiveData from ViewModel once, it should be also from the onCreate as it's the entry point to the activity and apart from config changes this method called only once. So, it's safe to observe it over there rather than during onResume which will be called multiple times during activity lifecycle. (The main issue your code wasn't working, so as a fix you only call your API method from ViewModel during resume)

ViewModel:

class MyAccountViewModel(context: Application) : AndroidViewModel(context) {
    private val _accountResponseData = MutableLiveData<My_account_base_response?>()
    val accountResponseData: MutableLiveData<My_account_base_response?>
        get() = _accountResponseData

    init {
        loadAccountData()
    }

    fun loadAccountData() {
        val token: String = SharedPrefManager.getInstance(getApplication()).user.access_token.toString()
        RetrofitClient.instance.fetchUser(token)
            .enqueue(object : Callback<My_account_base_response> {
                override fun onFailure(call: Call<My_account_base_response>, t: Throwable) {
                    Log.d("res", "" + t)
                    _accountResponseData.value = null
                }

                override fun onResponse(
                    call: Call<My_account_base_response>,
                    response: Response<My_account_base_response>
                ) {
                    var res = response

                    if (res.body()?.status == 200) {
                        _accountResponseData.value = response.body()
                    } else {
                        try {
                            val jObjError =
                            JSONObject(response.errorBody()!!.string())
                            Toast.makeText(
                                getApplication(),
                                jObjError.getString("user_msg"),
                                Toast.LENGTH_LONG
                            ).show()
                        } catch (e: Exception) {
                            Log.e("errorrr", e.message)
                        }
                    }
                }
            })
    }
}
  1. Don't make initial API call along with LiveData creation, it's okay to do in most of cases but if you're updating LiveData on response of that call then it's good to make it separately like during init block.

  2. It's good practice not to allow Ui (Activity/Fragments) to modify LiveDatas of ViewModel directly. So, that's good sign you're following such pattern by having private MutableLiveData exposed as public LiveData, but do it correctly as suggested.

  3. Side note: Your view model doesn't need to be LifecycleObserver. LifecycleObserver is used for some custom class/component which needs to be managed by their self by silently observing/depending on activity lifecycle independently. That's not the use case of ViewModel.


The only thing that I found why your code wasn't working correctly is because you were creating & observing ViewModel & LiveData over & over again as new objects from onResume method where you called hello() method.

Let me know if something don't make sense or missing.

Orthostichy answered 15/10, 2020 at 15:24 Comment(3)
have you seen the problem? --> #64353252Pahari
@apj123 Yes, I looked into question and seems like the solution provided by epicpandaforce is correct. All you're missing is few dependencies from gradle according to that code. I.e. ViewModel-ktx etc.Orthostichy
hey need help here --> #64532397Pahari

© 2022 - 2024 — McMap. All rights reserved.