Android Architecture Componentsを使ったサンプルを作るにあたって学んだことをメモ代わりに残していきたいと思います。
自分はそれぞれ単体でどう機能するのか理解し、その後組み合わせて使うことで理解が深まったので、それぞれ単体だとどういう使い方ができるのかを簡単に紹介してみたいと思います。
ViewModel
今回触ってみて一番使うのが簡単な割に、嬉しい機能だと思ったのがViewModelです。
気に入った点を挙げてみると、
1. 画面回転時のonDestroyを生き抜く
今までIcepickやPikkelを使って画面回転時の状態保存をしていた方が多いと思いますが、今後はViewModelを使用するとより簡単に状態保存ができます。
最小構成で簡単にその機能を試せるのはGoogleCodeLabsのサンプルstep2です。
気をつけるところは生成するときに直接newするのではなくViewModelProviders経由で取得するところくらいでしょうか。
サンプルではLifecycleActivityを使用していますが、AppCompatActivityやFragmentからでも使用可能です。
2. Fragment間で共有できる
ViewModelProviders.of
に親Activityを渡してあげると子Fragment間でのデータ共有ができます。拙作のサンプルからで申し訳ないのですが、以下のように書くことでMainViewModelを両Fragment間で共有することができます。
class BookMarkFragment : LifecycleFragment() {
private val mainViewModel by lazy { ViewModelProviders.of(activity).get<MainViewModel>() }
}
class ArticleFragment : LifecycleFragment() {
private val mainViewModel by lazy { ViewModelProviders.of(activity).get<MainViewModel>() }
}
3. 画面が破棄されるタイミングがわかる
これまではonCreateなどのライフサイクルイベントをPresenterなどへ渡し、Pub/Subの購読や解除を行なっていたのが、画面が破棄されるタイミングでonClearedメソッドが呼ばれるのでViewModel生成時に購読、破棄時に解除できるのでViewModelがライフサイクルを意識する必要がありません。
Lifecycle
ライフサイクルを持つActivityやFragment(LifecycleOwner)が、ライフサイクルイベントをフックしたい任意のオブジェクト(LifecycleObserver)に指定されたライフサイクルイベントを伝えることができます。
例えばPresenterにライフサイクルイベントを伝えたい時は以下のように書きます。
- ライフサイクルイベントをフックするPresenterにLifecycleObserverをimplementsし、@OnLifecycleEventから任意のライフサイクルを伝える
- ライフサイクルオーナーとなるActivityやFragmentはLifecycleActivity,LifecycleFragmentを継承し、lifecycle.addObserver(LifecycleObserverImpl)をする
class Presenter : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun onCreate() {
// do something
}
}
class MainActivity : LifecycleActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val presenter : Presenter = Presenter()
lifecycle.addObserver(presenter)
}
LiveData
LiveDataはLifecycleと共に使います。
EventBusやRxJavaのBehaviorSubjectのように、データ変更時に通知することができます。
これまでの通知機構との違いは
- RxLifecycleなど使わずともライフサイクルが安全な状態の時だけ通知してくれる。
- 一度購読したら解除を自動で行ってくれる。
これで忌々しいFragmentのIllegalStateExceptionも楽に回避できそうです。
こちらも最小構成だとGoogleCodeLabsのサンプルstep3_solutionが理解しやすかったです。
データに変更があった時はLiveDataのsetValueメソッドを使います。
// Update the elapsed time every second.
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
final long newValue = (SystemClock.elapsedRealtime() - mInitialTime) / 1000;
// setValue() cannot be called from a background thread so post to main thread.
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
mElapsedTime.setValue(newValue);
}
});
}
}, ONE_SECOND, ONE_SECOND);
サンプルだとHandlerを使っていますが、非同期処理の場合はpostValueを使うことも可能です。
// Update the elapsed time every second.
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
final long newValue = (SystemClock.elapsedRealtime() - mInitialTime) / 1000;
mElapsedTime.postValue(newValue);
}
}, ONE_SECOND, ONE_SECOND);
雑まとめ
安全にデータ変更通知をさせてくれるのがLifecycleとLiveData、画面回転対応する場合はViewModel、LiveDataはViewModelで保持する。
次はRoomも使ってみます。
お世話になった記事
Android Architecture Components Lifecycle, LiveData and ViewModel 詳解
Android Architecture Components 感想
Android Architecture Components ViewModel 和訳