web-dev-qa-db-ja.com

双方向データバインディング(xml形式)、ObservableField、BaseObservableのどちらを使用する必要がありますか?

しばらくデータバインディングを使用しましたが、現在でもJDK 8およびAPI 24では使用できません。データバインディングをより簡単に使用する方法をまだ見つけています。しかし、次の方法を使用して正確な双方向データバインディングを実行すると(私の考えでは、双方向データバインディングはここにあります( 双方向バインディングとは) )。起こった。

1。双方向データバインディング(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。モデルクラスを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);
   }
}

モデルクラスはBaseObservableクラスに拡張する必要があり、ゲッターメソッドには "@ Bindable"およびセッターメソッドは、メソッドnotifyPropertyChange()を、バインディングxmlの対応する名前で呼び出す必要があります。

私の質問は、3つのバインディング方法の欠点と利点を知りたいです。もちろん、私は最初の方が簡単になることを知っています。しかし、ドキュメントやウェブサイトで見つけた瞬間があります。そして次の瞬間に姿を消した。公式ドキュメントは明確な発表なしに変更されます。私はまだ最初の方法を使用する必要があるのか​​疑問に思うので、方法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>

活動クラス

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

Student_XML2WAY.Javaは、双方向のバインディングでは機能しません。これは、そのための要件を満たさないためです(BaseObservableBindableなど)。

Student_Extendのように、モデルに直接アクセスする場合は、BaseObservableを使用します。 ActivityStudent_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);
    }
}

そこで、StudentViewModelActivityのインスタンスを作成し、それをバインディングに設定します。 Pseudo-xmlは次のようになります。

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

したがって、ViewModelアプローチは「ビュー」に関連するほとんどすべてを外部委託するため、「より明確」です。 BindingAdapter、クリックメソッド、コンバーターメソッドをそこに配置し、Activityをクリーンな状態に保ちます。また、モデルを直接変更することもありません。このアプローチは、単純なクラスやプロジェクトにとってはやり過ぎになる可能性があります。 ;)

DataBindingとMVVMを使用した完全な例を確認したい場合は、これに関する Droids on roids アプローチを確認してください。

5
yennsarah

ゲッター/セッターを書く必要がないので、ObservableFieldアプローチが適していると思いますOR notifyPropertyChangedを呼び出します。

また、カスタムオブジェクト_ObservableField<Student> studentField_があり、_Android:text="@{viewModel.studentField.name}_を使用している場合、studentField.set(newStudent)を呼び出すとテキストが更新されます。

RxJavaは非常に便利です。 ObservableFieldは_rx.Observable_に、またはその逆に簡単に変換できます。これにより、Rx演算子を使用できます。興味がある場合は、ここで実装を確認できます。 FieldUtils.Java

0
Manas Chaudhari