简体   繁体   English

双向数据绑定(在xml中),ObservableField,BaseObservable,我应该用哪个双向数据绑定?

[英]Two-way databinding(in xml), ObservableField, BaseObservable , which one I should use for the two-way databinding?

I have used data-binding for a while, even now it is not available for JDK 8 and API 24 now. 我已经使用了数据绑定一段时间了,即使现在它也不适用于JDK 8和API 24。 I still find a way to use the data binding in a easier way. 我仍然找到一种以更简单的方式使用数据绑定的方法。 But when I use the following way to do the exact two-way data binding(In my mind, the two-way data binding is the thing like here( What is two way binding? ), somethings strange is happened. 但是当我使用以下方式进行精确的双向数据绑定时(在我看来,双向数据绑定就像这里( 什么是双向绑定? ),有些奇怪的事情发生了。

1. Two-way databinding(in xml) 1.双向数据绑定(以xml为单位)

android:text="@={testStr}"

This is not mentioned in the official documentation( https://developer.android.com/topic/libraries/data-binding/index.html , this page is usually updated, may be it is changed now). 在官方文档中没有提到https://developer.android.com/topic/libraries/data-binding/index.html ,此页面通常会更新,现在可能会更改)。 But it is available to bind the variable to the xml. 但它可以将变量绑定到xml。

2. ObservableField for the attributes 2. ObservableField属性

Example from here ( https://developer.android.com/topic/libraries/data-binding/index.html#observablefields ) 这里的示例( https://developer.android.com/topic/libraries/data-binding/index.html#observablefields

private static class User {
   public final ObservableField<String> firstName =
       new ObservableField<>();
   public final ObservableField<String> lastName =
       new ObservableField<>();
   public final ObservableInt age = new ObservableInt();
}

3. Extend the model class to the BaseObservable 3.将模型类扩展为BaseObservable

private static class User extends BaseObservable {
   private String firstName;
   private String lastName;
   @Bindable
   public String getFirstName() {
       return this.firstName;
   }
   @Bindable
   public String getLastName() {
       return this.lastName;
   }
   public void setFirstName(String firstName) {
       this.firstName = firstName;
       notifyPropertyChanged(BR.firstName);
   }
   public void setLastName(String lastName) {
       this.lastName = lastName;
       notifyPropertyChanged(BR.lastName);
   }
}

The model class must be extended to the BaseObservable class, and also the getter method must be annotated with "@Bindable" and the setter method need to call the method notifyPropertyChange() with corresponding naming in the binding xml. 必须将模型类扩展为BaseObservable类,并且必须使用“@Bindable”注释getter方法,并且setter方法需要使用绑定xml中的相应命名调用方法notifyPropertyChange()

My question is, I would like to know the drawback and the advantages for three binding methods. 我的问题是,我想知道三种绑定方法的缺点和优点。 Of course, I know the first one will be easier. 当然,我知道第一个会更容易。 But some moment I found in the documentation and in some website. 但是我在文档和某些网站上找到了一些时刻。 And it disappeared in the next moment. 它在下一刻消失了。 The official documentation is changed without any clear announcement. 官方文档在没有任何明确声明的情况下更改。 I still wonder should I use the first method so I have to prepare to change the the method 2 or 3. 我仍然想知道我应该使用第一种方法,所以我必须准备改变方法2或3。

Student_XML2WAY.java Student_XML2WAY.java

public class Student_XML2WAY {
    private int age;
    private String name;
    public int getAge() {
        return age;
    }
    public void setAge(int pAge) {
        age = pAge;
    }
    public String getName() {
        return name;
    }
    public void setName(String pName) {
        name = pName;
    }
}

Student_ObserField.java Student_ObserField.java

public class Student_ObserField {
    private ObservableInt age;
    private ObservableField<String> name;
    public Student_ObserField() {
        age = new ObservableInt();
        name = new ObservableField<>();
    }
    public ObservableInt getAge() {
        return age;
    }
    public ObservableField<String> getName() {
        return name;
    }
}

Student_Extend.java Student_Extend.java

public class Student_Extend  extends BaseObservable{
    private int age;
    private String name;

    @Bindable
    public int getAge() {
        return age;
    }
    public void setAge(int pAge) {
        age = pAge;
        notifyPropertyChanged(BR.student3);
    }
    @Bindable
    public String getName() {
        return name;
    }
    public void setName(String pName) {
        name = pName;
        notifyPropertyChanged(BR.student3);
    }
}

activity_main.xml activity_main.xml中

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="student1"
            type="example.com.testerapplication.sp.bean.Student_XML2WAY"/>

        <variable
            name="student2"
            type="example.com.testerapplication.sp.bean.Student_ObserField"/>

        <variable
            name="student3"
            type="example.com.testerapplication.sp.bean.Student_Extend"/>

    </data>

    <LinearLayout

        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
      >

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={student1.name}"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{student2.name}"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{student3.name}"/>
        <Button
            android:id="@+id/btn1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="update"/>
    </LinearLayout>
</layout>

Activity class 活动类

public class MainActivity extends AppCompatActivity {
    private Student_XML2WAY mStudent1;
    private Student_ObserField mStudent2;
    private Student_Extend mStudent3;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding = DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.activity_main, null, false);
        mStudent1 = new Student_XML2WAY();
        mStudent1.setName("XML First");
        mStudent2 = new Student_ObserField();
        mStudent2.getName().set("ObserField Second");
        mStudent3 = new Student_Extend();
        mStudent3.setName("Extend Third");
        binding.setStudent1(mStudent1);
        binding.setStudent2(mStudent2);
        binding.setStudent3(mStudent3);
        setContentView(binding.getRoot());
        binding.btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mStudent1.setName("Student1");
                mStudent2.getName().set("Student2");
                mStudent3.setName("Student3");
            }
        });
    }
}

Your Student_XML2WAY.java won't work with 2-way Binding, since it does not fulfill the requirements to do so ( BaseObservable , Bindable or something like that). 您的Student_XML2WAY.java不适用于双向绑定,因为它不满足这样做的要求( BaseObservableBindable或类似的东西)。

I would use BaseObservable if I will directly access the model, just like in your Student_Extend . 如果我将直接访问模型,我将使用BaseObservable ,就像在Student_Extend I will have an instance of Student_Extend in my Activity and I will set the variable in onCreate : 我将在我的Activity有一个Student_Extend实例,我将在onCreate设置变量:

Student mStudent = new Student("John Doe", 42); //
binding.setStudent(mStudent);
//later:
mStudent.setAge(37);

If implemented correctly, this will also change the Age in your UI (as well as in your model). 如果正确实施,这也将改变UI(以及模型中)的Age

If you do not want to access your model directly and want to use a ViewModel, I work with ObervableFields : 如果您不想直接访问模型并希望使用ViewModel,我可以使用ObervableFields

public class Student {
    private String name;
    private int age;
    //Corresponding setters and getters
}


public class StudentViewModel {
    private ObservableField<Student> mStudentField = new ObservableField<>();

    //if I have a large model class, and only want to use some fields, 
    //I create some getters (and setters, for the two way attributes)
    //Something like this:

    public int getAge() {
        return mStudentField.get().getAge();
    }
    public void setAge(int newAge) {
        return mStudentField.get().setAge(newAge);
    }
}

So, I create an instance of StudentViewModel in my Activity and set it to the binding. 因此,我在Activity创建了一个StudentViewModel实例,并将其设置为绑定。 Pseudo-xml would look like this: 伪xml看起来像这样:

<layout>
    <data>
        <variable name="studentViewModel" 
                  type="locaction.of.StudentViewModel"> <!-- or do an import -->
    </data>
    <EditText 
        android:text="@={studentViewModel.age}"/>
</layout>

So, the ViewModel approach is "clearer" since you outsource almost everything that has to do with views. 因此, ViewModel方法更“清晰”,因为您几乎将所有与视图有关的内容外包。 Put your BindingAdapter , click methods, converter methods there and keep your Activity clean. 把你的BindingAdapter ,点击方法,转换器方法放在那里,保持你的Activity干净。 Also, you do not directly change your model. 此外,您不直接更改您的模型。 This approach can be an overkill for simple classes and projects. 对于简单的类和项目,这种方法可能过度。 ;) ;)

If you want to see a full, example that uses DataBinding and MVVM, check out Droids on roids approach on this. 如果你想看一个完整的,使用DataBinding和MVVM的例子,请查看Droids on roids方法。

I feel that ObservableField approach is the way to go as there's no need to write getters/setters OR invoke notifyPropertyChanged . 我觉得ObservableField方法是ObservableField的,因为不需要编写getter / setter或调用notifyPropertyChanged

Also, if you have a custom object ObservableField<Student> studentField , and you use android:text="@{viewModel.studentField.name} , the text does get updated when you invoke studentField.set(newStudent) . 此外,如果您有一个自定义对象ObservableField<Student> studentField ,并且您使用android:text="@{viewModel.studentField.name} ,则在您调用studentField.set(newStudent)时文本会更新。

I find RxJava very useful. 我发现RxJava非常有用。 ObservableField can be easily converted to rx.Observable and vice versa. ObservableField可以很容易地转换为rx.Observable ,反之亦然。 This allows use of Rx operators. 这允许使用Rx运算符。 In case you are interested, you can check the implementation here: FieldUtils.java 如果您感兴趣,可以在此处检查实现: FieldUtils.java

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM