【Android】LiveDataを使った双方向Data Binding
LiveDataを使ってデータをViewに即座に反映させる方法はお馴染みですが、ViewからViewModelへリアクティブに制御する事例はまだ少ないため、ここではMediatorLiveDataを使ってその機能を実装してみたいと思います。
コードは以下の記事を参考にさせていただきました。ありがとうございます。
コード
まずはレイアウトです。
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" tools:context=".MainActivity"> <data> <variable name="viewModel" type="com.example.twowaydatabinding01.MainActivityViewModel" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.google.android.material.textfield.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="ユーザ名" android:layout_margin="8dp"> <com.google.android.material.textfield.TextInputEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:text="@={viewModel.username}"/> </com.google.android.material.textfield.TextInputLayout> <com.google.android.material.textfield.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="パスワード" android:layout_margin="8dp"> <com.google.android.material.textfield.TextInputEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:text="@={viewModel.password}"/> </com.google.android.material.textfield.TextInputLayout> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:enabled="@{viewModel.canSubmit}" android:onClick="@{() -> viewModel.onClick()}" android:text="LOGIN" /> </LinearLayout> </layout>
次に要となるViewModelです。
MainActivityViewModel.kt
package com.example.twowaydatabinding01 import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import timber.log.Timber class MainActivityViewModel : ViewModel() { val username = MutableLiveData<String>() val password = MutableLiveData<String>() private fun isValid(): Boolean { return !username.value.isNullOrBlank() && !password.value.isNullOrBlank() } val canSubmit = MediatorLiveData<Boolean>().also { result -> result.addSource(username) { result.value = isValid() } result.addSource(password) { result.value = isValid() } } fun onClick() { Timber.d(username.value + " - " + password.value) } }
最後にActivityです。
MainActivity.kt
package com.example.twowaydatabinding01 import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.databinding.DataBindingUtil import androidx.lifecycle.ViewModelProvider import com.example.twowaydatabinding01.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main) val viewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java) binding.viewModel = viewModel binding.lifecycleOwner = this } }
実行
よくあるログイン画面の構成です。ユーザ名とパスワードに何かしら入力されるまではLOGINボタンは押せません。ViewModelでユーザ名とパスワードの入力を監視し、両方入力された瞬間にボタンを有効化しています。再びどちらか一方でも空になるとボタンは無効化されます。
まとめ
LiveDataを使って双方向のDataBindingを行うことができました。UIをリアクティブにすることで、ユーザ操作を円滑にするための手助けをすることができます。積極的に取り入れていきたいですね。
参考
- https://qiita.com/YusukeIwaki/items/3fb4e10ac87fa1c7f6ba
- https://it.senatus.jp/android-livedata%E3%81%AE2-way-%E3%83%90%E3%82%A4%E3%83%B3%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%81%8C%E5%8B%95%E3%81%8B%E3%81%AA%E3%81%8F%E3%81%A6%EF%BC%92%E6%97%A5%E6%BD%B0%E3%81%97%E3%81%9F/
- https://developer.android.com/topic/libraries/data-binding/two-way