Communicate between Fragments and Activities — SharedViewModel

Rajat Dhamija
AppyHigh Blog
Published in
3 min readSep 12, 2020
Business vector created by pikisuperstar

Communication is one of the most important aspects for any developer. They will always have to communication between the components and at the same time keep in mind that it is the best and most modular way to do that. There are many ways this can be achieved, the most basic thing is creating a static field which might eventually lead to memory leaks 😕. So obviously you need a better and optimised way to do this!

To avoid memory leaks developers may follow the approach of binding the fragment to a particular activity and using something like :

(homeActivity as HomeActivity).sendDataToHomeActivity()

So what is wrong with this approach? Your code reusability decreases! And I am pretty sure you want it to be reusable. Before ViewModel came into picture Google used to recommend to use an interface, for this approach you were needed to have an interface which was implemented by you activity, child fragments used to hold a reference that would refer to the parent activity, and data was passed through the interface methods.

Activity — Fragment Communication with interface (without ViewModel)

Lets consider a case wherein HomeActivity has two fragments and whenever you write something in FragmentOne it is reversed and written in FragmentTwo. This will involve a bunch of code and quite a handling on both side of the components! So, here comes ViewModel to our rescue 😎

SharedViewModel

Using SharedViewModel you will be able to communicate between the fragments and activity wherein both the fragments and activity share the same ViewModel.

Note: Do add the dependency for LiveData and ViewModel

Create a SharedViewModel

class SharedViewModel : ViewModel(){
val inputString = MutableLiveData<String>()

fun notifyChange(newString : String){
inputString.value = newString
}
}

FragmentOne

class FragmentOne : Fragment() {

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_one, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val model = ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
model.inputString.observe(viewLifecycleOwner, Observer {
inputField.text = it.reversed()
})

}
}

FragmentTwo

class FragmentTwo : Fragment() {
lateinit var model: SharedViewModel

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_two, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
model = ViewModelProvider(requireActivity()).get(SharedViewModel::class.java)
button.setOnClickListener { model.notifyChange("Rajat") }
}
}
Activity — Fragment Communication with ViewModel

Understanding the working:

  • We have create a host activity name HomeActivity which has two child fragments named FragmentOne and FragmentTwo
  • In both of the fragments, we have on object for SharedViewModel which is same for both the fragments as the host activity is same.
  • In the FragmentTwo, we are sending the message on button click, which sets the value of inputText - LiveData in the SharedViewModel.
  • Then, in the FragmentOne, we are observing the change in the inputText - LiveData, and whenever the message is coming, we are updating the data in inputField.

Liked my work? Buy me a coffee.

--

--