英文:
android viewmodel with/without baseObservable
问题
以下是您要求的翻译内容:
我试图在Android中使用ViewModel,在MainViewModel.java中编写了以下代码:
public class MainViewModel extends ViewModel {
private String textView;
private String editText;
//@Bindable
public String getTextView(){
return textView;
}
private void setTextView(String value){
textView=value;
}
//@Bindable
public TextWatcher getEditTextWatcher() {
return new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
setTextView(s.toString());
}
//...
};
}
}
而在ActivityMain.xml中,我编写了以下代码:
<TextView
android:text="View-Model / Data-Binding"
android:layout_width="match_parent"
android:layout_height="40dp"/>
<TextView
android:id="@+id/main_text_view"
android:text="@{mainvm.textView}"
android:layout_width="match_parent"
android:layout_height="40dp"/>
<EditText
android:id="@+id/main_edit_text"
app:textChangeListener="@{mainvm.editTextWatcher}"
android:layout_width="match_parent"
android:layout_height="40dp"/>
我遇到了两个错误:
找不到接受参数类型为 'android.text.TextWatcher' 的 <android.widget.EditText app:textChangeListener> 的 setter 方法
如果绑定适配器提供了 setter 方法,请检查适配器的注解是否正确,并且参数类型是否匹配。
以及,
错误:找不到符号类 ActivityMainBindingImpl
有些文章使用 @Bindable 注解并扩展 BaseObservable,但这不是ViewModel的做法。
所以我的问题是如何解决这个问题?
英文:
I was trying to view-model in android, so for MainViewModel.java I wrote this :
public class MainViewModel extends ViewModel {
private String textView;
private String editText;
//@Bindable
public String getTextView(){
return textView;
}
private void setTextView(String value){
textView=value;
}
//@Bindable
public TextWatcher getEditTextWatcher() {
return new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
setTextView(s.toString());
}
...
};
}
}
And in the ActivityMain.xml I wrote this :
<TextView
android:text="View-Model / Data-Binding"
android:layout_width="match_parent"
android:layout_height="40dp"/>
<TextView
android:id="@+id/main_text_view"
android:text="@{mainvm.textView}"
android:layout_width="match_parent"
android:layout_height="40dp"/>
<EditText
android:id="@+id/main_edit_text"
app:textChangeListener="@{mainvm.editTextWatcher}"
android:layout_width="match_parent"
android:layout_height="40dp"/>
I'm getting 2 errors:
Cannot find a setter for <android.widget.EditText app:textChangeListener> that accepts parameter type 'android.text.TextWatcher'
If a binding adapter provides the setter, check that the adapter is annotated correctly and that the parameter type matches.
And,
error: cannot find symbol class ActivityMainBindingImpl
Some article uses @Binable annotation extending BaseObservable, which is not a ViewModel thing.
So my question how can I solve this ?
答案1
得分: 6
你不能在同一个类中同时扩展BaseObservable
和ViewModel
。你可以在ViewModel
内部使用ObservableFields。
你需要使用双向数据绑定,通过添加一个继承自BaseObservable
的类。
在这个类中,为你需要观察的文本创建一个字段;然后在其getter方法上添加@Bindable
注解,并在其setter方法内调用notifyPropertyChanged()
。
ViewModel
public class MainViewModel extends ViewModel {
Observer mObserver = new Observer();
Observer getObserver() {
return mObserver;
}
public static class Observer extends BaseObservable {
private String text;
@Bindable
public String getText() {
return text;
}
public void setText(String value) {
text = value;
notifyPropertyChanged(BR.text);
}
}
}
Activity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding mActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
MainViewModel mViewModel = new ViewModelProvider(this).get(MainViewModel.class);
mActivityMainBinding.setObserver(mViewModel.getObserver());
}
}
Layout
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="observer"
type="com.zain.android.twowaydatabindingedittextobservable.MainViewModel.Observer" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{observer.text}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/etName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@={observer.text}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvName" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
希望这对你有所帮助。
英文:
You cannot extend both BaseObservable
and ViewModel
in the same class. You can use ObservableFields inside of the ViewModel
.
You need to use Two-way databinding by adding a class that extends from BaseObservable
Within this class, create a field for the text you need to observe; then annotate its getter with @Bindable
and call notifyPropertyChanged()
within its setter
ViewModel
public class MainViewModel extends ViewModel {
Observer mObserver = new Observer();
Observer getObserver() {
return mObserver;
}
public static class Observer extends BaseObservable {
private String text;
@Bindable
public String getText() {
return text;
}
public void setText(String value) {
text = value;
notifyPropertyChanged(BR.text);
}
}
}
Activity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding mActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
MainViewModel mViewModel = new ViewModelProvider(this).get(MainViewModel.class);
mActivityMainBinding.setObserver(mViewModel.getObserver());
}
}
Layout
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="observer"
type="com.zain.android.twowaydatabindingedittextobservable.MainViewModel.Observer" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{observer.text}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/etName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@={observer.text}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvName" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Wish that can help you
答案2
得分: 1
你需要创建一个 BindingAdapter 来正确使用 DataBinding。更多详细信息可以在这里阅读 链接。
例如,创建一个适用于 EditText 的 BindingAdapter:
@BindingAdapter("addEditTextWatcher")
fun bindEditText(editText: EditText, stringTextWatcher: StringTextWatcher) {
val string = editText.text.toString()
stringTextWatcher.setString(editText.text.toString())
editText.addTextChangedListener(stringTextWatcher)
}
然后,在你的 ViewModel 中创建一个 TextWatcher 实例,以便在 .xml 文件中绑定它,就像这样:
<EditText
android:id="@+id/main_edit_text"
app:textChangeListener="@{mainvm.editTextWatcher}"
android:layout_width="match_parent"
android:layout_height="40dp"
addIntEditTextWatcher="@{viewModel.yourTextWatcher}"
/>
英文:
You need to create a BindingAdapter to properly use DataBinding. You can read more details here
For example to create for EditText
@BindingAdapter("addEditTextWatcher")
fun bindEditText(editText: EditText, stringTextWatcher: StringTextWatcher) {
val string = editText.text.toString()
stringTextWatcher.setString(editText.text.toString())
editText.addTextChangedListener(stringTextWatcher)
}
Then you need to create a TextWatcher instance in your ViewModel to bind it in .xml like this
<EditText
android:id="@+id/main_edit_text"
app:textChangeListener="@{mainvm.editTextWatcher}"
android:layout_width="match_parent"
android:layout_height="40dp"
addIntEditTextWatcher="@{viewModel.yourTextWatcher}"
/>
答案3
得分: 0
以下是翻译好的内容:
我之前毫无理由地让事情变得复杂化了。这是我的代码:
public class MyViewModel extends ViewModel{
private Observable<String> data = new Observable<>("");//初始化为空字符串,以防止崩溃
public String getData(){
return data.get();//如果我返回可观察对象本身,那么在类外部就会变成可变的,对吧
}
public void setData(String data){
data.setValue(data);//如果我接受可观察对象作为参数,那么会改变数据的引用,这就是为什么传递字符串
}
}
在 XML 中:
<TextView
android:id="@+id/main_text_view"
android:text="@{myvm.data}"
...
/>
<EditText
android:id="@+id/main_edit_text"
android:text="@{myvm.data}"
....
/>
然后像往常一样将其绑定到 Activity 或 Fragment。
英文:
I was making thing complicated for no reason. Here is my code :
public class MyViewModel extends ViewModel{
private Observable<String> data=new Observable<>("");//initializing with empty string, so that it doesn't crash
public String getData(){
return data.get();//if I return the observable itself that will become mutable, outside the class right
}
public void setData(String data){
data.setValue(data);//if I accept Observable as parameter that will change reference of data, that's why passing string
}
}
In xml:
<TextView
android:id="@+id/main_text_view"
android:text="@{myvm.data}"
...
/>
<EditText
android:id="@+id/main_edit_text"
android:text=@{myvm.data}
....
/>
And bind this to Activity or Fragment as usual.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论