J'ai utilisé la liaison de données pendant un certain temps, même maintenant, elle n'est plus disponible pour JDK 8 et API 24. Je trouve toujours un moyen d'utiliser plus facilement la liaison de données. Mais lorsque j'utilise la méthode suivante pour effectuer la liaison de données bidirectionnelle exacte (Dans mon esprit, la liaison de données bidirectionnelle est la même chose qu'ici ( Qu'est-ce qu'une liaison bidirectionnelle? ), quelque chose d'étrange est arrivé.
1. Liaison de données bidirectionnelle (en xml)
Android:text="@={testStr}"
Ceci n'est pas mentionné dans la documentation officielle ( https://developer.Android.com/topic/libraries/data-binding/index.html , cette page est généralement mise à jour, peut-être est changé maintenant). Mais il est disponible pour lier la variable au XML.
2. ObservableField pour les attributs
Exemple à partir d'ici ( 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. Etend la classe de modèle à 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);
}
}
La classe de modèle doit être étendue à BaseObservable class, et la méthode getter doit être annotée avec "@Bindable" et la méthode setter doit appeler la méthode notifyPropertyChange ( ) avec la dénomination correspondante dans le fichier XML de liaison.
Ma question est la suivante: j'aimerais connaître les inconvénients et les avantages de trois méthodes de reliure. Bien sûr, je sais que le premier sera plus facile. Mais quelques instants j’ai trouvé dans la documentation et sur un site Web. Et il a disparu dans l'instant suivant. La documentation officielle est modifiée sans aucune annonce claire. Je me demande toujours si je dois utiliser la première méthode, donc je dois me préparer à changer la méthode 2 ou 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>
Classe d'activité
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");
}
});
}
}
Votre Student_XML2WAY.Java
ne fonctionnera pas avec la liaison bidirectionnelle, car il ne remplit pas les conditions pour le faire (BaseObservable
, Bindable
ou quelque chose du genre).
J'utiliserais BaseObservable
si j'accédais directement au modèle, tout comme dans votre Student_Extend
. J'aurai une instance de Student_Extend
dans ma Activity
et je définirai la variable dans onCreate
:
Student mStudent = new Student("John Doe", 42); //
binding.setStudent(mStudent);
//later:
mStudent.setAge(37);
Si implémenté correctement, cela modifiera également la Age
dans votre interface utilisateur (ainsi que dans votre modèle).
Si vous ne souhaitez pas accéder directement à votre modèle et souhaitez utiliser un ViewModel, je travaille avec 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);
}
}
Donc, je crée une instance de StudentViewModel
dans ma Activity
et la mets à la liaison. Le pseudo-xml ressemblerait à ceci:
<layout>
<data>
<variable name="studentViewModel"
type="locaction.of.StudentViewModel"> <!-- or do an import -->
</data>
<EditText
Android:text="@={studentViewModel.age}"/>
</layout>
Ainsi, l'approche ViewModel
est "plus claire" puisque vous externalisez presque tout ce qui concerne les points de vue. Mettez votre BindingAdapter
, cliquez sur méthodes, méthodes de conversion et gardez votre Activity
propre. En outre, vous ne modifiez pas directement votre modèle. Cette approche peut être exagérée pour des classes et des projets simples. ;)
Si vous voulez voir un exemple complet qui utilise DataBinding
et MVVM, consultez Droids on roids approche sur cela.
Je pense que l’approche ObservableField
est la voie à suivre car il n’est pas nécessaire d’écrire des getters/setters OR invoke notifyPropertyChanged
.
De même, si vous avez un objet personnalisé ObservableField<Student> studentField
et que vous utilisez Android:text="@{viewModel.studentField.name}
, le texte est mis à jour lorsque vous appelez studentField.set(newStudent)
.
Je trouve RxJava très utile. ObservableField
peut être facilement converti en rx.Observable
et vice versa. Cela permet d'utiliser des opérateurs Rx. Si cela vous intéresse, vous pouvez vérifier l’implémentation ici: FieldUtils.Java