The observer in my MainActivity is not being triggered when the string data is being changed
Here is my MainActivity:
package com.example.translator
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.widget.EditText
import android.widget.TextView
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.example.translator.databinding.ActivityMainBinding;
import com.example.translator.databinding.FragmentTranslateBinding
import com.example.translator.viewmodellivedata.TranslateViewModel
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: TranslateViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding =ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.translateText.text = "translation.."
viewModel = ViewModelProvider(this).get(TranslateViewModel::class.java)
viewModel.currentWord().observe(this, Observer {
binding.translateText.text = it.toString()
Log.d("current", it.toString())
})
}
}
TranslateViewModel:
package com.example.translator.viewmodellivedata
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.LiveData
class TranslateViewModel : ViewModel() {
private var _currentWord = MutableLiveData<String>()
fun currentWord(): LiveData<String> {
return _currentWord
}
fun setCurrentWord(word: String) {
_currentWord.value = word
}
}
TranslateFragment:
package com.example.translator
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.text.TextWatcher
import android.text.Editable
import android.view.View
import android.view.ViewGroup
import android.util.Log
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.example.translator.databinding.FragmentTranslateBinding
import com.example.translator.viewmodellivedata.TranslateViewModel
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
* A simple [Fragment] subclass.
* Use the [translateFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class translateFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
private var _binding: FragmentTranslateBinding? = null // View Binding instance
private val binding get() = _binding!!
private lateinit var viewModel: TranslateViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentTranslateBinding.inflate(inflater, container, false)
val view = binding.root
viewModel = ViewModelProvider(this).get(TranslateViewModel::class.java)
binding.editText.hint = "Write something..."
// Add a TextWatcher to the EditText
binding.editText.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
// This method is called before text is changed
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
// This method is called as text is changing
}
override fun afterTextChanged(s: Editable?) {
// This method is called after text has changed
val enteredText = s.toString()
//binding.editText.setText(enteredText)
//binding.translateText.text
viewModel.setCurrentWord(enteredText)
//viewModel.currentWord().observe(viewLifecycleOwner, Observer { word ->
// // This code will execute when the LiveData value changes
/// Log.d("current", word.toString())
// })
// Reattach the TextWatcher
// You can perform translation or any other actions here with the enteredText
}
})
//val view = binding.root
//viewModel = ViewModelProvider(this).get(TranslateViewModel::class.java)
return view
}
override fun onDestroyView() {
super.onDestroyView()
_binding = nul
l
}
companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment translateFragment.
*/
// TODO: Rename and change types and number of parameters
@JvmStatic
fun newInstance(param1: String, param2: String) =
translateFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
I'm trying to have the TextView show what the user is typing in an fragment editview using live data observer but every time I type something in the edittext the textview does to recipreacte it and the observer is not being triggered in my MainActivity
Inside the Fragment, you need to pass
requireActivity()to the ViewModelProvider constructor instead of passingthis. The argument you pass is what scope the ViewModel will be loaded in, so if they don’t match, they will be distinct instances.By the way, it is much easier to use
by viewModels()and in the fragment,by activityViewModels()rather than fooling with the view model provider.