Two-way databinding(in xml), ObservableField, BaseObservable ,我应该使用哪一个来进行双向数据绑定?
Two-way databinding(in xml), ObservableField, BaseObservable , which one I should use for the two-way databinding?
我已经使用了一段时间的数据绑定,即使现在 JDK 8 和 API 24 现在也不可用。我仍然找到一种以更简单的方式使用数据绑定的方法。但是当我使用下面的方式进行精确的双向数据绑定时(在我看来,双向数据绑定就是这里的东西(What is two way binding?),奇怪的事情发生了。
1.双向数据绑定(in xml)
android:text="@={testStr}"
官方文档中没有提到(https://developer.android.com/topic/libraries/data-binding/index.html,这个页面经常更新,现在可能已经改了)。但是可以将变量绑定到 xml.
2。属性的 ObservableField
这里的例子 (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。将模型 class 扩展到 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);
}
}
模型class必须扩展到BaseObservableclass,并且getter方法必须用[=48注释=]"@Bindable" 和 setter 方法需要在绑定 xml 中调用相应命名的方法 notifyPropertyChange()。
我的问题是,我想知道三种绑定方式的优缺点。当然,我知道第一个会更容易。但是有一段时间我在文档和某些网站上找到了。并且在下一刻就消失了。官方文档在没有任何明确通知的情况下发生了变化。我仍然想知道我是否应该使用第一种方法,所以我必须准备更改方法 2 或 3。
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
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
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
<?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");
}
});
}
}
您的 Student_XML2WAY.java
无法使用双向绑定,因为它不满足这样做的要求(BaseObservable
、Bindable
或类似的东西)。
如果我直接访问模型,我会使用 BaseObservable
,就像在您的 Student_Extend
中一样。我将在我的 Activity
中有一个 Student_Extend
的实例,我将在 onCreate
:
中设置变量
Student mStudent = new Student("John Doe", 42); //
binding.setStudent(mStudent);
//later:
mStudent.setAge(37);
如果实施正确,这也会改变 UI(以及您的模型)中的 Age
。
如果您不想直接访问您的模型并想使用 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);
}
}
因此,我在我的 Activity
中创建了一个 StudentViewModel
实例并将其设置为绑定。伪 xml 看起来像这样:
<layout>
<data>
<variable name="studentViewModel"
type="locaction.of.StudentViewModel"> <!-- or do an import -->
</data>
<EditText
android:text="@={studentViewModel.age}"/>
</layout>
因此,ViewModel
方法是 "clearer",因为您外包了几乎所有与视图有关的东西。将您的 BindingAdapter
、点击方法、转换器方法放在那里并保持您的 Activity
干净。此外,您不会直接更改模型。
这种方法对于简单的 类 和项目来说可能有点矫枉过正。 ;)
如果您想查看使用 DataBinding
和 MVVM 的完整示例,请查看 Droids on roids 方法。
我觉得 ObservableField
方法是可行的方法,因为不需要编写 getters/setters 或调用 notifyPropertyChanged
。
另外,如果您有一个自定义对象 ObservableField<Student> studentField
,并且您使用 android:text="@{viewModel.studentField.name}
,当您调用 studentField.set(newStudent)
.
时,文本会更新
我发现 RxJava 非常有用。 ObservableField
可以很容易地转换为 rx.Observable
,反之亦然。这允许使用 Rx 运算符。如果您有兴趣,可以在此处查看实现:FieldUtils.java
我已经使用了一段时间的数据绑定,即使现在 JDK 8 和 API 24 现在也不可用。我仍然找到一种以更简单的方式使用数据绑定的方法。但是当我使用下面的方式进行精确的双向数据绑定时(在我看来,双向数据绑定就是这里的东西(What is two way binding?),奇怪的事情发生了。
1.双向数据绑定(in xml)
android:text="@={testStr}"
官方文档中没有提到(https://developer.android.com/topic/libraries/data-binding/index.html,这个页面经常更新,现在可能已经改了)。但是可以将变量绑定到 xml.
2。属性的 ObservableField
这里的例子 (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。将模型 class 扩展到 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);
}
}
模型class必须扩展到BaseObservableclass,并且getter方法必须用[=48注释=]"@Bindable" 和 setter 方法需要在绑定 xml 中调用相应命名的方法 notifyPropertyChange()。
我的问题是,我想知道三种绑定方式的优缺点。当然,我知道第一个会更容易。但是有一段时间我在文档和某些网站上找到了。并且在下一刻就消失了。官方文档在没有任何明确通知的情况下发生了变化。我仍然想知道我是否应该使用第一种方法,所以我必须准备更改方法 2 或 3。
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
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
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
<?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");
}
});
}
}
您的 Student_XML2WAY.java
无法使用双向绑定,因为它不满足这样做的要求(BaseObservable
、Bindable
或类似的东西)。
如果我直接访问模型,我会使用 BaseObservable
,就像在您的 Student_Extend
中一样。我将在我的 Activity
中有一个 Student_Extend
的实例,我将在 onCreate
:
Student mStudent = new Student("John Doe", 42); //
binding.setStudent(mStudent);
//later:
mStudent.setAge(37);
如果实施正确,这也会改变 UI(以及您的模型)中的 Age
。
如果您不想直接访问您的模型并想使用 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);
}
}
因此,我在我的 Activity
中创建了一个 StudentViewModel
实例并将其设置为绑定。伪 xml 看起来像这样:
<layout>
<data>
<variable name="studentViewModel"
type="locaction.of.StudentViewModel"> <!-- or do an import -->
</data>
<EditText
android:text="@={studentViewModel.age}"/>
</layout>
因此,ViewModel
方法是 "clearer",因为您外包了几乎所有与视图有关的东西。将您的 BindingAdapter
、点击方法、转换器方法放在那里并保持您的 Activity
干净。此外,您不会直接更改模型。
这种方法对于简单的 类 和项目来说可能有点矫枉过正。 ;)
如果您想查看使用 DataBinding
和 MVVM 的完整示例,请查看 Droids on roids 方法。
我觉得 ObservableField
方法是可行的方法,因为不需要编写 getters/setters 或调用 notifyPropertyChanged
。
另外,如果您有一个自定义对象 ObservableField<Student> studentField
,并且您使用 android:text="@{viewModel.studentField.name}
,当您调用 studentField.set(newStudent)
.
我发现 RxJava 非常有用。 ObservableField
可以很容易地转换为 rx.Observable
,反之亦然。这允许使用 Rx 运算符。如果您有兴趣,可以在此处查看实现:FieldUtils.java