web-dev-qa-db-fra.com

Liaison de données bidirectionnelle (en xml), ObservableField, BaseObservable, lequel dois-je utiliser pour la liaison de données bidirectionnelle?

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");
            }
        });
    }
}
9
Long Ranger

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.

3
yennsarah

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

0
Manas Chaudhari