Search code examples
androidmvvmandroid-livedatamutablelivedata

Data not transferring from one fragment to another using ViewModel and LiveData


I have 2 fragments:

HomeFragment ListFragment

I am trying to send data from HomeFragment to ListFragment using ViewModel and LiveData but i am not able to do so. ListFragment is not updating the value.

So i have 2 buttons: Groceries and Electronics in HomeFragment Whichever button i click on HomeFragment should be updated to ListFragment

MainActivityViewModel.kt

class MainActivityViewModel : ViewModel() {

    private val itemType = MutableLiveData<String>()
    val itemTypeData : LiveData<String>
    get() = itemType

    init {
        itemType.value = "No Item"
    }

    fun updateItemType(type: Int){
        if(type == 0) itemType.value = "Groceries"
        else itemType.value = "Electronics"
    }

}

HomeFragment.kt

class HomeFragment : Fragment() {

    private lateinit var mainViewModel : MainActivityViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val binding : FragmentHomeBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)

        mainViewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)
        binding.viewModel = mainViewModel
        binding.lifecycleOwner = this

        binding.tvGroceries.setOnClickListener {
            mainViewModel.updateItemType(0)
            it.findNavController().navigate(R.id.action_homeFragment_to_listFragment)
        }
        binding.tvElectronics.setOnClickListener {
            Log.d("sagar", "clicked ")
            mainViewModel.updateItemType(1)
            it.findNavController().navigate(R.id.action_homeFragment_to_listFragment)
        }

        return binding.root
    }

}

ListFragment.kt

class ListFragment : Fragment() {
    private lateinit var mainViewModel : MainActivityViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        val binding : FragmentListBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_list, container, false)

        mainViewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)
        binding.viewModel = mainViewModel
        binding.lifecycleOwner = this
        return binding.root
    }

}

fragment_list.xml

<?xml version="1.0" encoding="utf-8"?>
<layout>
    <data>
        <variable
            name="viewModel"
            type="com.example.ecompractice.MainActivityViewModel" />
    </data>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/frameLayout2"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ListFragment">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="55dp"
        android:layout_marginTop="54dp"
        android:text="@{viewModel.itemTypeData}"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

ListFragment Always Print: No Item

I have tried watching tutorials and reading some articles but none helped.


Solution

  • So after 2 hours, i figured out what the problem was.

    Problem was being caused by this line:

    mainViewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)

    Here, i am making each of these fragments owner of themselves. But instead, we are supposed to make the activity the owner of all these fragments so that data can be transferred between these fragments.