I have an activity, TabBarActivity
that hosts a fragment, EquipmentRecyclerViewFragment
. The fragment receives the LiveData callback but the Activity does not (as proofed with breakpoints in debugging mode). What's weird is the Activity callback does trigger if I call the ViewModel's initData
method. Below are the pertinent sections of the mentioned components:
TabBarActivity
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initVM() setContentView(R.layout.activity_nav) val equipmentRecyclerViewFragment = EquipmentRecyclerViewFragment() supportFragmentManager .beginTransaction() .replace(R.id.frameLayout, equipmentRecyclerViewFragment, equipmentRecyclerViewFragment.TAG) .commit() navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener) } var eVM : EquipmentViewModel? = null private fun initVM() { eVM = ViewModelProviders.of(this).get(EquipmentViewModel::class.java) eVM?.let { lifecycle.addObserver(it) } //Add ViewModel as an observer of this fragment's lifecycle eVM?.equipment?.observe(this, loadingObserver)// eVM?.initData() //TODO: Not calling this causes Activity to never receive the observed ∆ } val loadingObserver = Observer<List<Gun>> { equipment -> ...}
EquipmentRecyclerViewFragment
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) columnCount = 2 initVM() } //MARK: ViewModel Methods var eVM : EquipmentViewModel? = null private fun initVM() { eVM = ViewModelProviders.of(this).get(EquipmentViewModel::class.java) eVM?.let { lifecycle.addObserver(it) } //Add ViewModel as an observer of this fragment's lifecycle eVM?.equipment?.observe(this, equipmentObserver) eVM?.initData() } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_equipment_list, container, false) if (view is RecyclerView) { // Set the adapter val context = view.getContext() view.layoutManager = GridLayoutManager(context, columnCount) view.adapter = adapter } return view }
EquipmentViewModel
class EquipmentViewModel(application: Application) : AndroidViewModel(application), LifecycleObserver { var equipment = MutableLiveData<List<Gun>>() var isLoading = MutableLiveData<Boolean>() fun initData() { isLoading.setValue(true) thread { Thread.sleep(5000) //Simulates async network call var gunList = ArrayList<Gun>() for (i in 0..100){ gunList.add(Gun("Gun "+i.toString())) } equipment.postValue(gunList) isLoading.postValue(false) } }
The ultimate aim is to have the activity just observe the isLoading
MutableLiveData boolean, but since that wasn't working I changed the activity to observe just the equipment LiveData to minimize the number of variables at play.
LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state.
[...] However ViewModel objects must never observe changes to lifecycle-aware observables, such as LiveData objects.
liveData declared as val can't change, but you can always update the value of LiveData because it is MutableLiveData . Any change in value of liveData notifies all of its active observers. LiveData is always observed inside a UI Lifecycle owner, which can be an Activity or a Fragment.
To get same reference of ViewModel
of your Activity
you need to pass the same Activity instance, you should use ViewModelProviders.of(getActivity)
. When you pass this
as argument, you receive instance of ViewModel
that associates with your Fragment
.
There are two overloaded methods:
ViewModelProvider.of(Fragment fragment) ViewModelProvider.of(FragmentActivity activity)
For more info Share data between fragments
I put this code inside the onActivityCreated
fragment, don't underestimate getActivity ;)
if (activity != null) { globalViewModel = ViewModelProvider(activity!!).get(GlobalViewModel::class.java) } globalViewModel.onStop.observe(viewLifecycleOwner, Observer { status -> Log.d("Parent Viewmodel", status.toString()) })
This code helps me to listening Parent ViewModel changes in fragment.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With