GoogleI/O行ってないけどAndroid Jetpack気になったので調べてみた
先週はGoogle I/Oでしたね。現地にも行かずリアルタイムで見ることもしませんでしたが、TwitterのTLから現地のレポートを見てそわそわしていました。
KeynoteでのAndroid P発表も騒がれましたが、何やらJetpack
とやらが話題の様子。Googleがdocumentを揃えてくれているので、読んでみました。
なお、翻訳ではなくメモ程度です。
What’s
公式サイトによると、
Jetpack is a set of libraries, tools and architectural guidance to help make it quick and easy to build great Android apps.
とのこと。後述する内訳も見ると、これまでGoogleが提供していたArchitectureComponentを含んだコンポーネント群、のような感じでしょうか。
What’s included
4つの区分があるようです。
Foundation
Android開発の全領域に関わるコンポーネントが入っています。AppCompatよく分からんけど使っとくか、みたいな時期がすごく長かったので、個人的にこれがちゃんと分類されたことはすごく嬉しいです。
Architecture
- Data Binding
- Lifecycles
- LiveData
- Navigation
- Paging
- Room
ここがいわゆるArchitecture Componentが入るカテゴリのようですね。データの永続化、データ変更の通知などを行うものから、ライフサイクルのつらみをラッピングしてくれるものまで詰まっています。 正直まだ全部は分かってないので詳しくは書きません。
Navigationのところは、Androidアプリのデザイン自体とも絡んできそうなので、早めに読みたいです。
Behavior
- Download manager
- Media & playback
- Notifications
- Permissions
- Sharing
- Slices
制作しているアプリが、他のアプリやOSなどと上手くやっていくところをお手伝いしてくれるコンポーネント群、という理解です。
特に気になったのはNotificationsとSlicesです。前に業務でウィジェット(ホームスクリーンに出てくる方)を作ることがあったのですが、通知やらUI微妙に作りづらい問題やらで結構苦労しました。この辺がきれいに作れるようになってるといいなぁ……。(まだ見てない)
UI
- Animation & transitions
- Auto
- Emoji
- Fragment
- Layout
- Palette
- TV
- Wear OS by Google
当たり前なのですが、UIというだけあって、handset以外のモバイル端末から車までもをサポートするコンポーネントが揃っています。スマホだけがAndroidアプリ開発じゃないんだ。
加えて、おなじみFragmentから絵文字、アニメーションを対象としたコンポーネントが入っています。
How to use
具体的な使い方は各コンポーネント群をインストールして……となるのです が、Jetpackベースでアプリを作る時のハンズオン?のようなものも用意されていました。
Android Studioの3.2+が必須条件です。まだアイコンが緑色の人(2018/05/12時点)は、公式サイトからPreview版をインストールしましょう。 Stable版とは違う名前でインストールされたのでご安心を。
次に、新しくプロジェクトを作ります。
すると……
新顔がいますね。Activity & Fragment + ViewModel
だそうです。
ActivityやFragmentとそれらに紐づくlayout配下のXMLの名前を聞かれます。さらに、ViewModelの名前やFragment package pathを入力する項目がありますね。
とりあえずそのままにしてFinish
を押すと……
Activity, Fragment, ViewModelが出来ています。Activity以外はuiパッケージに押し込めてくれています。
ソースはかなりシンプルですが、以下のとおりです。
Activity
... class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) if (savedInstanceState == null) { supportFragmentManager.beginTransaction() .replace(R.id.container, MainFragment.newInstance()) .commitNow() } } }
Fragment
... class MainFragment : Fragment() { companion object { fun newInstance() = MainFragment() } private lateinit var viewModel: MainViewModel override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { return inflater.inflate(R.layout.main_fragment, container, false) } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java) // TODO: Use the ViewModel } }
ViewModel
import android.arch.lifecycle.ViewModel class MainViewModel : ViewModel() { // TODO: Implement the ViewModel }
ページ上に進めていくと、ViewModelを実装したりArchitectureComponentのNavigation
の香りを感じたりできます。
Guide to App Architecture
Guide to App Architecture | Android Developers
ちょっと長いので箇条書きで。
- アプリのコンポーネントの中にアプリのデータや状態を保持してはいけない
- 全てのアプリのコンポーネントは、個別に起動されたりいつでも捨てられる可能性があるため
- コンポーネント間は依存せず独立しているべき
- 重要な原理は2つ
- 関心の分離をしよう
- ActivityやFragmentからUI操作やOSとのやり取り以外のコードを排除する
- UIを(できれば永続化した)モデルから操作しよう
- OSによるリソース解放でアプリのプロセスがdestroyされたとしてもユーザーがデータを失わないため
- ネットワークの状態がよくない時でもアプリを起動しておくため
- Modelとはアプリ内のデータを扱うコンポーネント
- 関心の分離をしよう
UIを作る時は?
ViewModel
を使おう- 表示するデータを保持しておくため
- Viewや設定の変更(画面の向きの変更によるactivityの再生成など)とは関係なしにデータを扱える
LiveData
を使おう- アプリの他のコンポーネントから保持しているデータの変更を検知するため
- データの変更をobserveしてUIを更新したいときには、propertyを
LiveData
で包んだ後、observe()
メソッド内で処理を行う
データを取得するときは?
- REST APIと通信を行うライブラリを使おう
- Serviceという形でメソッドを準備する
- 今回は
Retrofit
を使う
ViewModel
にデータの取得とオブジェクトへのマッピングの責務を追わせるのはやめよう- メンテナンス性向上のため
関心の分離のため
Repository
オブジェクトを作ろう- コンポーネント間の依存性を管理しよう
ViewModelとRepositoryを接続するときは?
ViewModelからrepositoryのメソッド呼ぶだけです。次!
データをキャッシュしたいときは?
- Fragmentに戻るたびにAPIをcallするのはやめよう
- 貴重なネットワークの帯域を浪費することになる
- ユーザーに通信完了まで待たせることになる
val cached = CacheObject.get(id) if (cached != nil) { return cached } // 以降、APIからの取得処理
そっか、インメモリキャッシュってこんなシンプルだったんだと考え直しました。SQLiteやらrealmやらライブラリ先行で技術を追っていると大事なことを忘れてしまいますね。
データを永続化したいときは?
Room
を使おう
テストしたいときは?
- UI & Interaction
- この時だけEspressoなどを使ってUIの実装のテストをしよう
- ViewModel
JUnit
でテストをしようRepository
をモックににする必要がある
- Repository
- DAO
- instrumentationテストを行う必要がある
JUnit
のSupportSQLiteOpenHelper
を使えばUnitテストができるが、端末とローカルPCとでSQLiteのバージョンに違いがあると困る
- Service
- Mock化しよう
- 外部に依存しないテストにするため、通信が走らないでテストをしよう
- ライブラリはたくさんあるけど、okhttp/mockwebserverとかおすすめ
- TestingArtifacts
TODO
- 古くなったデータの更新処理
- ネットワークの状態をユーザーに通知する
Note
- データの整合性を保つには、data sourceを1つにしよう
- 同じデータを返す複数のAPIのエンドポイントがあるとき、データの齟齬が発生する
- 全てのデータ取得を内部のDBなどに統一すれば解決できる
大筋は以上です!!長かった!~後半JetpackというよりはAACの話だけどまあいっか~
実際はコードラボ風味になっているので、手を動かしながら進めていただきたく!
AACの紹介ではなくて、直面した問題ベースでの設計の考え方をベースに進めてくれたので、かなり分かりやすいし研修の教材としてもいい感じなのではないでしょうか。
まだAACで触わりたりないところがあるので、各コンポーネントの内部もしっかり読んでいきたいです。