我无法理解 Fragment + ViewModel 范例如何与 EditText 等 View 一起使用。
它是一个 EditText,显然会在 View ( fragment )中进行修改。但我也希望能够在 ViewModel 中修改它:例如删除其文本。
这是 Fragment 类中的代码:
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
...
comment = mViewModel.getComment();
comment.observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(String s) {
commentView.setText(s);
}
});
...
commentView.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
mViewModel.setComment(String.valueOf(s));
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) { }
});
如您所见,我设置了一个观察者,因此当我更改 MutableLiveData 的值时, View 会发生变化。我设置了一个观察者,这样当我(使用应用程序时)更改 View 的值时,MutableLiveData 就会发生变化。
这是 ModelView 类的代码:
public void addRegister() {
...
String comment = this.comment.getValue();
...
this.comment.setValue("");
当我运行应用程序时,没有弹出错误,但它挂起。我猜是因为无限循环。 我应该如何使用此 View + ViewModel 范例来处理 EditTexts?我不明白什么?
提前非常感谢!
最佳答案
由于接受的答案并不在所有情况下都适合我(当通过 EditText 本身以外的其他方式在 ViewModel 中更改文本时),而且我也不想使用数据绑定(bind),所以我想出了以下解决方案,其中一个标志跟踪由 TextWatcher 启动的更新,并在调用观察者时中断循环:
这是我在 Kotlin 中的代码。 对于 Activity :
class SecondActivity : AppCompatActivity() {
/** Flag avoids endless loops from TextWatcher and observer */
private var textChangedByListener = true
private val viewModel by viewModels<SecondViewModel>()
private lateinit var binding:SecondActivityBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = SecondActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.editText.addTextChangedListener(object: TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { }
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { }
override fun afterTextChanged(editable: Editable?) {
textChangedByListener = true
viewModel.editText = editable.toString()
}
})
viewModel.editTextLiveData.observe(this) { text -> setEditTextFromViewModel(text) }
}
private fun setEditTextFromViewModel(text: String?) {
if (!textChangedByListener) {
//text change was not initiated by the EditText itself, and
//therefore EditText does not yet contain the new text.
binding.editText.setText(text)
} else {
//Don't move that outside of else, because it would then
//immediately overwrite the value set by TextWatcher
//which is triggered by the above setText() call.
textChangedByListener = false
}
}
}
为了完整起见,还有 ViewModel:
class SecondViewModel() : ViewModel()
{
var editText: String
get() {
return editTextLiveData.value ?: "InitialLiveData"
}
set(value) {
editTextLiveData.value = value
}
var editTextLiveData = MutableLiveData<String>()
}
以防万一,您不熟悉 View 绑定(bind):您可以替换
binding.editText
与
findViewById(R.id.editTextId) 作为 EditText
。
关于java - 与EditText冲突: Watcher to the View + Observer to the MutableLiveData,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59875950/