MainActivity中LiveData Observer未响应Fragment数据更新问题
我期望通过LiveData实现MainActivity的TextView实时显示Fragment中EditText的输入内容,但当在Fragment的EditText中输入内容时,MainActivity中的Observer未被触发,TextView也没有做出响应。相关代码如下:
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 = null } 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) } } } }
核心问题
当前代码的问题在于Fragment和MainActivity各自创建了独立的ViewModel实例,导致两者绑定的LiveData不是同一个对象,Fragment更新数据后,Activity观察的LiveData完全没有变化。
修改步骤
Fragment中共享Activity的ViewModel实例
在Fragment的onCreateView方法中,获取ViewModel时,将ViewModelProvider(this)改为ViewModelProvider(requireActivity()),这样Fragment就会使用Activity的ViewModelStore,和Activity共享同一个ViewModel实例:// 原代码 // viewModel = ViewModelProvider(this).get(TranslateViewModel::class.java) // 修改后 viewModel = ViewModelProvider(requireActivity()).get(TranslateViewModel::class.java)优化命名规范(可选但推荐)
将Fragment类名translateFragment改为TranslateFragment,符合Kotlin类名首字母大写的规范,避免代码风格不一致。初始化LiveData默认值(可选)
在ViewModel中给_currentWord设置默认值,避免首次观察时出现空值:private var _currentWord = MutableLiveData<String>("")
修改后的Fragment关键代码片段
class TranslateFragment : Fragment() { // ... 其他代码不变 override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { _binding = FragmentTranslateBinding.inflate(inflater, container, false) val view = binding.root // 使用Activity的ViewModelStore获取共享实例 viewModel = ViewModelProvider(requireActivity()).get(TranslateViewModel::class.java) // ... 其他代码不变 return view } // ... 其他代码不变 }
完成以上修改后,Fragment输入内容时,会更新共享ViewModel里的LiveData,Activity的Observer就能实时收到数据变化,TextView也会同步更新。
内容的提问来源于stack exchange,提问作者Python coder

