Home > Mobile >  How do you observe LiveDat outside a fragment
How do you observe LiveDat outside a fragment

Time:05-12

I have a TextView inside a Fragment. Using LiveData I am able to change the text from within the fragment. By using a button in the MainActivity (outside the fragment) I am trying to change the text in the TextView, but it is not working. Can someone help. Here is my code:

This is the MainActivity which has a button and a fragment

class MainActivity : AppCompatActivity() {
    var tg: ToneGenerator? = null
    private lateinit var btn: Button
    private lateinit var viewModel:ViewModel

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

        tg = ToneGenerator(AudioManager.STREAM_SYSTEM, 100)

        btn = findViewById(R.id.buttonTest1)

        viewModel = ViewModelProvider(this).get(ViewModel::class.java)

        btn.setOnClickListener {
            tg?.startTone(ToneGenerator.TONE_PROP_BEEP)
            viewModel.changeMLD()
        }
    }
}

This is the fragment which has a TextView


class Fragment : Fragment() {

    private lateinit var txt1: TextView
    public lateinit var viewModel:ViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        // Inflate the layout for this fragment
        val view: View = inflater.inflate(R.layout.fragment, container, false)

        txt1 = view.findViewById(R.id.txt1)

        viewModel = ViewModelProvider(this).get(ViewModel::class.java)

        viewModel.initiateMLD()

        viewModel.LD.observe(viewLifecycleOwner, Observer {
            txt1.setText("Count is " it)
        })

        return view
    }

}

This is the ViewModel with the LiveData


class ViewModel : ViewModel(){
    private var clickCount:Int = 0

    private var MLD = MutableLiveData<Int>()
    var LD : LiveData<Int> = getMLD()             // observer watches this variable

    fun initiateMLD(){
        MLD.value = 5
        clickCount = 5
    }

    fun getMLD():MutableLiveData<Int>{
        return MLD
    }

    fun changeMLD(){
        clickCount =2
        MLD.value = clickCount
    }
}

CodePudding user response:

In your fragment you've created viewModel using your fragment as the owner,

viewModel = ViewModelProvider(this).get(ViewModel::class.java)

Whereas to communicate with the activity you need to create viewModel object using activity as the owner. These are called sharedViewModels.

ViewModelProvider(requireActivity()).get(ViewModel::class.java)

You can read more about SharedViewModel in this codelab tutorial.

CodePudding user response:

You are using 2 different instances of ViewModel. ViewModelProvider creates one for your activity and one for your fragment. It is because they both are viewModelStoreOwners. If you want to use the same instance of ViewModel in both Fragment and Activity. It has to be activity scoped. You can do that like this


ViewModelProvider(requireActivity()).get(ViewModel::class.java)

  • Related