【问题标题】:android viewmodel with/without baseObservable带有/不带有 baseObservable 的 android viewmodel
【发布时间】:2020-07-18 15:43:28
【问题描述】:

我试图在 android 中查看模型,所以对于 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"/>

我收到 2 个错误:

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.

还有,

error: cannot find symbol class ActivityMainBindingImpl

有些文章使用@Binable注解扩展BaseObservable,这不是ViewModel的东西。

所以我的问题是如何解决这个问题?

【问题讨论】:

  • 要观察textView的值吗?
  • @Zain 不,我想在 textview 中显示 edittext 的值,使用 viewmodel

标签: java android mvvm viewmodel


【解决方案1】:

您不能在同一个类中同时扩展 BaseObservableViewModel。您可以在 ViewModel 中使用 ObservableFields

您需要通过添加从BaseObservable 扩展的类来使用Two-way databinding

在这个类中,为你需要观察的文本创建一个字段;然后用@Bindable 注释它的getter 并在它的setter 中调用notifyPropertyChanged()

视图模型

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);
        }
    }

}

活动

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 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>

希望能帮到你

【讨论】:

  • MainViewModel 中的 Observer 类是静态的有什么原因吗?您是否知道向Observer 提供参数(如数据库连接或项目 ID)的优雅解决方案?
  • @BrunoBieri 根据你的需要,可以是内部类,但是这里是静态内部类,只能使用外部类名访问,所以这里我限制了内部的实例化类要通过外部类...静态嵌套类无法访问非静态(实例)数据成员或方法...您可以根据需要将其设为非静态..请看here跨度>
  • 谢谢你的解释,我明白了。
  • 这方面文档不是很清楚,谢谢
【解决方案2】:

您需要创建一个 BindingAdapter 才能正确使用 DataBinding。您可以阅读更多详细信息here 例如为 EditText 创建

@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}"
/>

【讨论】:

  • 首先,它在 kotlin 中,所以我在 java 中转换它并尝试,它给了我 ...getBindEditText as an accessor or listener on the attribute. 和以前一样的旧 imp 错误
  • 奇怪也许你的 DataBinding 初始化不正确。添加活动代码和完整的 layout.xml 文件。我去看看
【解决方案3】:

我无缘无故地让事情变得复杂。这是我的代码:

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
     }
}

在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。

【讨论】:

  • 什么是 Observable?什么包?
猜你喜欢
  • 2018-10-20
  • 2019-07-17
  • 1970-01-01
  • 2019-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多