レイアウト ビューをアーキテクチャ コンポーネントにバインドする

AndroidX ライブラリに含まれるアーキテクチャ コンポーネントを使用すると、堅牢でテストとメンテナンスが容易なアプリを設計できます。データ バインディング ライブラリはアーキテクチャ コンポーネントとシームレスに連携し、UI の開発をさらに簡素化します。アプリのレイアウトはアーキテクチャ コンポーネントのデータにバインドできます。これにより、UI コントローラ�����イ����イ�������管理し、データの変更を UI に通知できます。

このページでは、アーキテクチャ コンポーネントをアプリに組み込み、データ バインディング ライブラリを最大限に活用する方法について説明します。

LiveData を使用してデータの変更について UI に通知する

LiveData オブジェクトをデータ バインディング ソースとして使用すると、データの変更について UI に自動的に通知できます。このアーキテクチャ コンポーネントについて詳しくは、LiveData の概要をご覧ください。

監視可能フィールドなどの Observable を実装するオブジェクトとは異なり、LiveData オブジェクトはデータ変更に登録されたオブザーバーのライフサイクルを認識しています。この知識には多くの利点があります。詳しくは LiveData を使用するメリットをご覧ください。Android Studio バージョン 3.1 以降では、データ バインディング コード内で監視可能なフィールドを LiveData オブジェクトに置き換えることができます。

バインディング クラスで LiveData オブジェクトを使用するには、ライフサイクル オーナーを指定して LiveData オブジェクトのスコープを定義する必要があります。次の例では、バインディング クラスをインスタンス化した後、アクティビティをライフサイクル オーナーとして指定しています。

Kotlin

class ViewModelActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // Inflate view and obtain an instance of the binding class.
        val binding: UserBinding = DataBindingUtil.setContentView(this, R.layout.user)

        // Specify the current activity as the lifecycle owner.
        binding.setLifecycleOwner(this)
    }
}

Java

class ViewModelActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Inflate view and obtain an instance of the binding class.
        UserBinding binding = DataBindingUtil.setContentView(this, R.layout.user);

        // Specify the current activity as the lifecycle owner.
        binding.setLifecycleOwner(this);
    }
}

次のセクションで説明するように、ViewModel ��ンポーネントを使用してデータをレイアウトにバインドできます。ViewModel コンポーネントでは、LiveData オブジェクトを使用してデータの変換や複数のデータソースの結合を行うことができます。次の例は、ViewModel 内のデータを変換する方法を示しています。

Kotlin

class ScheduleViewModel : ViewModel() {
    val userName: LiveData

    init {
        val result = Repository.userName
        userName = Transformations.map(result) { result -> result.value }
    }
}

Java

class ScheduleViewModel extends ViewModel {
    LiveData username;

    public ScheduleViewModel() {
        String result = Repository.userName;
        userName = Transformations.map(result, result -> result.value);
    }
}

ViewModel を使用して UI 関連のデータを管理する

データ バインディング ライブラリは ViewModel コンポーネントとシームレスに連携します。ViewModel は、レイアウトが監視してその変化に対応するデータを公開します。データ バインディング ライブラリで ViewModel コンポーネントを使用すると、UI ロジックをレイアウトからコンポーネントに移動でき、テストが容易になります。必要に応じて、データ バインディング ライブラリにより、ビューがデータソースからバインドまたはバインド解除されるようにします。残りの作業のほとんどは、正しいデータが公開されていることを確認することです。このアーキテクチャ コンポーネントについて詳しくは、ViewModel の概要をご覧ください。

ViewModel コンポーネントをデータ バインディング ライブラリで使用するには、ViewModel クラスから継承したコンポーネントをインスタンス化し、バインディング クラスのインスタンスを取得して、ViewModel コンポーネントをバインディング クラスのプロパティに割り当てる必要があります。次の例は、ライブラリでコンポーネントを使用する方法を示しています。

Kotlin

class ViewModelActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // Obtain the ViewModel component.
        val userModel: UserModel by viewModels()

        // Inflate view and obtain an instance of the binding class.
        val binding: UserBinding = DataBindingUtil.setContentView(this, R.layout.user)

        // Assign the component to a property in the binding class.
        binding.viewmodel = userModel
    }
}

Java

class ViewModelActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Obtain the ViewModel component.
        UserModel userModel = new ViewModelProvider(this).get(UserModel.class);

        // Inflate view and obtain an instance of the binding class.
        UserBinding binding = DataBindingUtil.setContentView(this, R.layout.user);

        // Assign the component to a property in the binding class.
        binding.viewmodel = userModel;
    }
}

次の例に示すように、レイアウトでは、バインディング式を使用して ViewModel コンポーネントのプロパティとメソッドを対応するビューに割り当てます。

<CheckBox
    android:id="@+id/rememberMeCheckBox"
    android:checked="@{viewmodel.rememberMe}"
    android:onCheckedChanged="@{() -> viewmodel.rememberMeChanged()}" />

監視可能な ViewModel を使用して、バインディング アダプターを詳細に管理する

Observable インターフェースを実装する ViewModel コンポーネントを使用して、データの変更について他のアプリ コンポーネントに通知できます。LiveData オブジェクトの使用方法と同様です。

LiveData のライフサイクル管理機能が失われた場合でも、LiveData オブジェクトを使用するよりも、Observable インターフェースを実装する ViewModel コンポーネントを使用することをおすすめします。Observable を実装する ViewModel コンポーネントを使用すると、アプリ内のバインディング アダプターをより詳細に制御できます。たとえば、このパターンでは、データが変更���れたときの通知をより細かく制御できます。また、カスタム メソッドを指定して、双方向データ バインディングの属性の値を設定することもできます。

監視可能な ViewModel コンポーネントを実装するには、ViewModel クラスから継承して Observable インターフェースを実装するクラスを作成する必要があります。オブザーバーが addOnPropertyChangedCallback() メソッドと removeOnPropertyChangedCallback() メソッドを使用して通知を登録または登録解除するときに、カスタム ロジックを指定できます。notifyPropertyChanged() メソッドでプロパティが変更されたときに実行されるカスタム ロジックを指定することもできます。次のコード例は、監視可能な ViewModel を実装する方法を示しています。

Kotlin

/**
 * A ViewModel that is also an Observable,
 * to be used with the Data Binding Library.
 */
open class ObservableViewModel : ViewModel(), Observable {
    private val callbacks: PropertyChangeRegistry = PropertyChangeRegistry()

    override fun addOnPropertyChangedCallback(
            callback: Observable.OnPropertyChangedCallback) {
        callbacks.add(callback)
    }

    override fun removeOnPropertyChangedCallback(
            callback: Observable.OnPropertyChangedCallback) {
        callbacks.remove(callback)
    }

    /**
     * Notifies observers that all properties of this instance have changed.
     */
    fun notifyChange() {
        callbacks.notifyCallbacks(this, 0, null)
    }

    /**
     * Notifies observers that a specific property has changed. The getter for the
     * property that changes must be marked with the @Bindable annotation to
     * generate a field in the BR class to be used as the fieldId parameter.
     *
     * @param fieldId The generated BR id for the Bindable field.
     */
    fun notifyPropertyChanged(fieldId: Int) {
        callbacks.notifyCallbacks(this, fieldId, null)
    }
}

Java

/**
 * A ViewModel that is also an Observable,
 * to be used with the Data Binding Library.
 */
class ObservableViewModel extends ViewModel implements Observable {
    private PropertyChangeRegistry callbacks = new PropertyChangeRegistry();

    @Override
    protected void addOnPropertyChangedCallback(
            Observable.OnPropertyChangedCallback callback) {
        callbacks.add(callback);
    }

    @Override
    protected void removeOnPropertyChangedCallback(
            Observable.OnPropertyChangedCallback callback) {
        callbacks.remove(callback);
    }

    /**
     * Notifies observers that all properties of this instance have changed.
     */
    void notifyChange() {
        callbacks.notifyCallbacks(this, 0, null);
    }

    /**
     * Notifies observers that a specific property has changed. The getter for the
     * property that changes must be marked with the @Bindable annotation to
     * generate a field in the BR class to be used as the fieldId parameter.
     *
     * @param fieldId The generated BR id for the Bindable field.
     */
    void notifyPropertyChanged(int fieldId) {
        callbacks.notifyCallbacks(this, fieldId, null);
    }
}

参考情報

データ バインディングの詳細については、次の参考情報をご覧ください。