从Dialog调用ViewModel的postValue后,MainActivity界面未更新
问题场景
混用Kotlin与Java开发,定义了如下MainViewModel:
class MainViewModel : ViewModel() { val textViewIP: MutableLiveData<String> = MutableLiveData() }
在DialogFragment的确认按钮点击事件中修改MutableLiveData的值:
private fun positiveButtonClicked() { prefManager.ip = editTextIP.text.toString().trim() mainViewModel.textViewIP.postValue(prefManager.ip) dismiss() }
MainActivity通过DataBinding绑定ViewModel,在Activity内直接修改值时UI能即时更新,但从DialogFragment修改后UI无变化,需重启APP才生效。疑问:是否需要添加Observer?该如何实现?
MainActivity相关代码:
private MainViewModel mainViewModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); mainViewModel = new ViewModelProvider(this).get(MainViewModel.class); activityMainBinding.setViewmodel(mainViewModel); activityMainBinding.setLifecycleOwner(this); ... mainViewModel.getTextViewIP().setValue(prefManager.getIp()); }
布局文件代码:
<TextView android:id="@+id/textViewIP" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{viewmodel.textViewIP}"/>
核心原因
问题本质是DialogFragment中获取的MainViewModel实例与Activity中的不是同一个。如果DialogFragment通过自身作为LifecycleOwner获取ViewModel,或者直接new实例,就会产生两个独立的ViewModel对象,修改的LiveData自然无法同步到Activity绑定的实例上。
解决方案
不需要额外添加Observer(DataBinding已经帮你完成了LiveData的观察工作),只需要确保DialogFragment获取的是与Activity相同的MainViewModel实例即可:
Kotlin版DialogFragment获取ViewModel
// 在DialogFragment中声明ViewModel,指定Activity作为LifecycleOwner private val mainViewModel: MainViewModel by viewModels( ownerProducer = { requireActivity() } )
Java版DialogFragment获取ViewModel
private MainViewModel mainViewModel; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 通过requireActivity()作为ViewModelProvider的Owner,获取与Activity一致的实例 mainViewModel = new ViewModelProvider(requireActivity()).get(MainViewModel.class); }
这样修改后,DialogFragment中操作的就是Activity绑定的同一个MainViewModel实例,调用postValue或setValue后,DataBinding会自动感知LiveData的变化并更新UI,无需重启APP。
补充说明
DataBinding在你设置activityMainBinding.setLifecycleOwner(this)后,会自动为布局中绑定的LiveData添加Observer,当LiveData数据变化时自动更新对应的UI控件。所以只要确保ViewModel实例唯一,就能实现跨组件的UI同步更新。
内容的提问来源于stack exchange,提问作者Pezcraft

