Android×MVI×Coroutineを提供するライブラリの紹介

Tsukamoto Takeshi
Jan 11, 2019 · 5 min read

本記事は github.om/itome/owl の紹介記事です。

OwlはMVIをベースにした新しいAndroidの状態管理ライブラリで、以下の機能を提供しています。

  • Reduxライクな状態管理
  • Coroutineを使った非同期処理の導入、Jobの管理、ViewModelとの統合
  • AACをもとにしたLifecycle awareなViewStateの通知

Owlは以上のことにのみ特化した小さなライブラリなので、ライブラリをインストールせずに実装パターンだけをプロジェクトに導入しても構いません。現状Javaはサポートしておらず、KotlinでのAndroid開発を前提にしています。

Owlは以下のライブラリに依存しています。

  • org.jetbrains.kotlinx:kotlinx-coroutines-core
  • org.jetbrains.kotlinx:kotlinx-coroutines-android
  • androidx.lifecycle:lifecycle-extensions

使い方

一番簡単なViewModelの実装は以下のとおりです。完全なサンプルアプリはsampleにあります。

Owlは OwlViewModel , Intent , Action , State からなります。それぞれのクラスには以下のようなシンプルなルールがあります。

Intent

Viewがどのような処理を行いたいかを表すsealedクラスです。 Intent をdispatchすることがViewが State を変更する唯一の方法です。 Intent をdispatchするときには現在の State によって Intent にわたすデータを変えたり、dispatchする Intent 自体を変えるべきではありません。そのようなことがしたい場合、 OwlViewModel#intentToActionState にアクセスしてください。

Action

実際に State に対してどのような変更をするかを表すsealedクラスです。

State

ViewModel層の現在のStateを表すdata classです。Viewはこのクラスのデータをもとに表示の変更を行います。 ViewModel層全体のなかで唯一状態を保持することができます。

OwlViewModel

OwlViewModel#intentToActionIntent から Action への変換と、 OwlViewModel#reducerAction から State への変換を行うクラスで、内部に State を保持します。 OwlViewModel 内では同期的な処理のみを行い、CallbackやCoroutineによる並列処理を書くことはできません。

Owlで非同期処理を行う

前述の通り、Owlでは OwlViewModel 内での非同期処理ができません。そのかわり、Coroutineによる非同期処理を行う Processor クラスを提供しています。 Processor の実装は以下のようになります。

ProcessorprocessAction メソッドを持ちます。 processActionOwlViewModel でActionが作成され、 reducer によって処理されると同時に呼ばれます。 Processor はそれ自体が CoroutineScope なので、 Processor 内部で非同期処理を行うことができます。処理が完了したら、 Processor#put メソッドによって同じく ActionOwlViewModel へ戻します。戻された Action は他の Action と同様に OwlViewModel#reducer によって処理されます。

最後に ProcessorOwlViewModel と接続するために、OwlViewModel のコンストラクタに Processor を渡します。

ProcessorOwlViewModel が破棄されると、同時にcloseされるので、実装者がcoroutineの Job を管理する必要はありません。

以下が図説です

Pros

Owlライブラリを使うことで以下の利点があります。

  • 各実装に制約がかかるため、チーム開発でメンバーごとのコードの差異を少なくすることができる。
  • Processorを分離していることで、State管理のコードと非同期処理のコードが分けられる
  • ViewModelはProcessorがあるかどうかに関わらず、Intent → Action → Stateの変更という処理の流れを作ることができる。(上図で青背景に囲まれたViewModelの中は、Processorと独立している)
  • テストが書きやすい。(入出力のストリームが一本なので、テストをパターン化できる)
  • IntentとActionを分けていることで、Viewから見たViewModelのインターフェースがシンプルになる。

Cons

  • Intentという用語が android.content.Intent と同じでややこしい。
  • Stateの変更を差分更新する仕組みがAndroidにはないので、Stateが複雑になったり描画コストの大きいデータをもたせたりするとパフォーマンスの悪化につながりやすい。
  • ボイラープレートのコードが増える。

最後に

意見や感想あれば@itometeamか、レポジトリのissueまでお願いします。外部からのフィードバックがほしいので、どんな意見でも歓迎です!

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade