ヴァル研究所 Advent Calendar 2021 23日目の記事です。
はじめまして。
BtoC開発チームで「駅すぱあと for Android」を担当している遠島と申します。
新卒2年目の社員で、Android開発を始めてからは1年と半年程になります。
今回の記事では、Android独自のコンポーネントをいくつか紹介してみたいと思います。
Android開発に興味はあるけど触ったことがない方や、これからAndroidエンジニアを目指す学生の方の参考になれば幸いです。
あくまで汎用的なコンポーネントだけに絞って紹介するので、読み進める中でもっといろいろ知りたいと思った方は、こちらのAndroid開発者向けの公式リファレンスを参照していただければと思います。
1. 画面を構築するActivity, Fragment
画面を作成する上で重要なコンポーネントとして、「Activity」と「Fragment」というクラスがあります。
ざっくり言うと、画面の大枠を構成するのがActivity。
そのActivityの中で動く画面がFragmentです。
大体のアプリには下タブがあり、それをタップして切り替えることができるし、タブ内でもいろいろな画面に遷移することができると思います。
イメージとしてはタブで切り替えるのがActivity、タブ内で画面を切り替えるのがFragmentというイメージです(最近のアプリではFragmentでどちらも行うケースもありますが、あくまでイメージです)。
概要としては以下の公式ページを参照いただくことをおすすめします。
これらの画面を構築するためのクラスを理解する上でのキーワードとしては、「ライフサイクル」だと思います。
ActivityクラスやFragmentクラスには「ライフサイクルメソッド」というメソッドが定義されており、画面が作成され、動作し、最終的に破棄されるまでの一連の流れがメソッドとして定義されています。
Androidアプリケーションでは、画面を作成する際にこのActivityクラスを継承したクラスを用意して、上記の各メソッドを上書きしながらアプリを作っていくのがメジャーなやり方だと思います。
Activityのライフサイクルについて見てみましょう。
パッとみてもどういうことか分からないですよね😅
上記のメソッドの概要をそれぞれざっくり書くと、以下のような感じかと思います。
- onCreate() - システムによってActivityが作成される前に呼ばれ、一回のみ実行する必要がある基本的なアプリの起動ロジックを実行する。 - onStart() - Activityがフォアグラウンドになり、操作可能になるための最後の準備を行う - onResume() - Activityが前面にきて、ユーザーとのやりとりを始められるようになる直前に呼び出される - onPause() - Activityがバックグラウンドに隠れるときに、呼ばれる。 - onStop() - ホーム画面に戻ったり、アプリが見えなくなるときに呼ばれる - onRestart() - onStop状態になっていたアクティビティが再び起動すると呼び出される - onDestroy() - アクティビティが破棄される前に呼び出される
このようにActivityのそれぞれのメソッドには、役割と呼び出されるタイミングがあり、これを理解しないまま実装すると思ったような挙動をしない可能性があります...
「バックグラウンド→フォアグラウンド時に表示されるはずのオブジェクトが消滅した...」
「なぜかアプリがクラッシュする...(本来してはいけない所で通信処理を走らせていた)」
などなど。
このActivityやFragmentにおけるライフサイクルという概念は、Android開発をする上では基本ですが、とても重要な概念です。
- アクティビティのライフサイクルについて | Android デベロッパー | Android Developers
- フラグメント | Android デベロッパー | Android Developers
2. 状態管理をするViewModel, LiveData
「ViewModel」は、上述したActivityやFragmentなどのUIコントローラで保持されている一時的なUI関連のデータを管理するのに利用するコンポーネントです。
役割としては大きく二つあり、一つはActivityなどからのDBアクセスや通信処理をViewModelに切り離すことでUIコントローラのソース肥大化を防ぐこと。
もう一つは先述の通り、UIコントローラの一時データの管理です。
Acitivityやフラグメントは、Androidフレームワークによって管理されていて、ユーザが意識的にアプリのタスクキルなどをしなくとも、Activityなどの破棄を行うことがあります。
例えば、画面回転した時ですね。
実はAndroidにおける画面回転時には、Activityインスタンスは再生成されています。
こうした際に、Activityインスタンスにメンバ変数として保持されていたデータは、このActivityの破棄と同時に消滅し、再作成が走った時も失われたデータは返ってきません。
ここで登場するのがViewModelです。
ViewModelは取得する時に、ライフサイクルオーナーというオブジェクトを設定することができ、そのオブジェクトにViewModelのライフサイクルが追従します。
上の画像で言うとActivityをライフサイクルオーナーに設定しており、そうした場合Activityのライフサイクルが完全に終了して初めて、ViewModelも破棄されます。
ViewModelは、ActivityやFragmentを意識したライフサイクルで設計されているため、画面の回転でそれらの再生成がされても生存し続けるようになっています。
ただし、注意点としては、Androidにはメモリが逼迫した際にシステムが自動でバックグラウンドにいるActivityのプロセスを終了する機能があり、ViewModelではその復元はできません。
その場合のデータ復元はデータベースやonSaveInstanceState()でのBundleへの書き出しを用いて行います。
次は「LiveData」です。
LiveDataは、ViewModel内のデータの更新をActivityやFragmentに監視させることで、更新時にViewの変更が行うことができるコンポーネントです。
LiveDataの値に変更があった際に、監視しているオブジェクトに通知をしてくれるObserverパターンが組み込まれています。
通知のタイミングとしては、監視者であるActivityやFragmentのライフサイクルに準拠します。
具体的に言うと、監視者であるライフサイクルの状態がSTARTEDもしくはRESMEDの場合に、LiveDataはアクティブな状態であると判断し値に変動があった際に通知するといった具合ですね。
これによってアプリデータが変更される度にUIを更新する必要がなく、UIのデータを常に最新に保つことができます。
3. データを保存するRoom
次はローカルデータベースにデータを保存する「Room」というコンポーネントです。
RoomはDB・Entity・DAOという3つのコンポーネントから構成されており、それらを用いることでデータベース(SQLite)上でデータを管理します。
それぞれをざっくり言うと、
- DB
- データベース(SQLiteと直接接続する部分)
- Entity
- テーブルを定義するクラス
- DAO
- データベースにアクセスするメソッドを格納するクラス
という認識で自分はいます。
それぞれのクラスを定義したら、DBインスタンスを作成して取得、あとはDBに紐づけたDAOからDBにアクセスするためのメソッドを呼び出すだけで、比較的お手軽にデータベース処理を実装することができます。
ただ注意点として、Androidでは、何も指定をしなければ全ての処理はUIスレッドというスレッドで処理が行われており、そこではDBアクセスや通信処理といった処理を行うことができません。
まとめ
今回はAndroid独自コンポーネントを基本的な物に絞ってご紹介してみました。
実際にしっかりとアプリを開発しようと思うと、
- スレッド管理(rxjava・coroutine)
- http通信(okhttp・retrofit)
- DI対応(dagger・dagger hilt)
などの学習が必要になってくるケースもありますが、今回は割愛します。
Android開発は覚えることも多く、1年半経った今でも実装には頭を悩ませる毎日ではありますが、それ以上に開発を進めるのが楽しいので、興味がある方はぜひAndroid開発を始めてみてください!
自分も現部署に配属されるまで、iPhoneしか使ってこなかったiOSユーザでしたが、今では自前の端末もAndroidにしているくらい魅力のあるOSです。
最後までお読みいただきありがとうございました。
次の24日目は、ヴァル研究所 CTOの見川さんの記事です!