現代の Android アプリケーションでは、Kotlin、AndroidX、Jetpack ライブラリ、Jetpack Compose が一般的に使われます。
プラットフォーム API は android.* に残り、AndroidX は androidx.* にバージョン互換の高水準 API を提供します。
アプリケーションパッケージには、プロセス全体の通常の main() メソッドではなく、システムが管理する複数のエントリーポイントがあります。
アプリケーションの分離 #
Android はインストールされたパッケージに Linux UID を割り当て、プライベートファイルを UID ベースの所有権で管理します。 アプリケーションプロセスは独自の Android Runtime インスタンスを実行し、パッケージ間のコンポーネント呼び出しには Binder IPC を使います。 実行時権限、SELinux、フレームワークサービスのチェックが UID の境界を補完します。
共有 UID はかつて同じ署名のパッケージで利用できましたが、パッケージ分離を弱めるため新規アプリケーションでは非推奨です。 アプリケーションはプライベートパスではなく、権限で保護したコンテンツプロバイダー、ドキュメントピッカー、 URI グラント、Binder サービスなどの明示的なインターフェースでデータを共有します。
コンポーネントとマニフェスト #
Android には 4 種類のコンポーネントがあります。
- アクティビティは、フォーカスされたユーザーインターフェースをホストします。
- サービスはアクティビティ UI なしで処理を実行します。長時間のユーザー向け処理にはフォアグラウンドサービス通知が必要で、 プラットフォームの制限を受けます。
- ブロードキャストレシーバーはブロードキャストに短時間で応答し、長い処理は適切なスケジューラーへ委譲します。
- コンテンツプロバイダーは
ContentResolverAPI を通じて構造化データを公開します。
マニフェストは、アプリケーションコンポーネント、権限、必要な場合のパッケージ可視性、最小 SDK レベル、機能、
アプリケーションメタデータを宣言します。インテントフィルターを持つコンポーネントが外部からアドレス可能になるのは、
android:exported の設定と適用される権限が許可する場合だけです。非公開コンポーネントはエクスポートしないでください。
インテントとコンポーネントの起動 #
明示的インテントは特定のコンポーネントを識別します。暗黙的インテントはアクション、データ、カテゴリ、任意の extras を記述し、 システムはエクスポートされたインテントフィルターに照合して解決します。暗黙的なサービスインテントは意図しないコンポーネントに解決される可能性があるため、 内部操作とサービスには明示的インテントを使います。
アクティビティは startActivity または Activity Result API で起動します。サービスは実行モデルに応じて
startService、startForegroundService、bindService を使います。コンテンツプロバイダーは ContentResolver を通じて操作を受け取ります。
即時実行が不要なバックグラウンド処理は、長時間存続するバックグラウンドサービスではなく、
WorkManager、または適切な場合は JobScheduler に置きます。
受信するすべてのインテント、extras、URI は信頼できない入力として扱います。API が許す場合は呼び出し元を検証し、 値を検証し、機密コンポーネントには権限を要求し、URI 権限は必要な範囲と期間に限って付与します。
アクティビティのライフサイクルと状態 #
システムは onCreate でアクティビティを生成し、onStart で表示可能にし、onResume で対話可能にします。
onPause はアクティビティがフォアグラウンドのフォーカスを失ったことを示し、速やかに戻る必要があります。
アクティビティが見えなくなると onStop が続き、表示中だけ必要なリソースを解放する適切な場所になります。
アクティビティオブジェクトは、finish が要求された場合やシステムがプロセスを回収した場合に破棄されます。
後者に備えて、onSaveInstanceState は小さく再構築可能な UI 状態を保存します。フレームワークは対応するビュー階層の状態を保存しますが、
アプリケーション状態はサイズとライフタイムに応じて ViewModel、saved-state handle、データベースなどの永続的な保存先に置きます。
ライフサイクルコールバックで上限のないネットワークトランザクションやデータベース移行を実行しないでください。
リソース #
Android のリソースシステムは res/ の項目を R.string.app_name のような生成識別子へコンパイルします。
各リソースは layout、drawable、mipmap、values、xml、font、menu、raw、anim、animator などの型付きトップレベルディレクトリに置きます。
assets/ に置いたアセットは R にコンパイルされず、AssetManager で開きます。
リソース修飾子は、構成、ロケール、画面サイズ、密度、向き、ナイトモードに対して最適な代替物を選びます。 修飾子は文書化された順序で使い、同じ修飾子型を繰り返してはなりません。デバイス構成が特殊な代替物に一致しない可能性があるため、 アプリケーションが参照するすべてのリソースに既定リソースを用意します。
Kotlin、Jetpack、Compose #
Kotlin は null 安全性、拡張関数、ラムダ、sealed 型、コルーチンを提供します。AndroidX と Jetpack はライフサイクル対応コンポーネント、
Navigation、Room、WorkManager、互換 API を提供します。lifecycleScope と viewModelScope はコルーチンを所有者に結び付けますが、
キャンセルされる場合でも処理をべき等にし、失敗を処理する必要はなくなりません。
Jetpack Compose は UI をコンポーザブル関数として表現します。アクティビティは setContent で Compose に入り、
コンポジションへ収集された監視可能な状態により、影響を受ける UI が再コンポーズされます。
LazyColumn は効率的な項目ベースのレイアウトを提供し、モディファイアはレイアウト、操作、装飾を表現します。
画面状態は ViewModel に保持し、コンポーザブルは主に状態の関数にし、ライフタイムがコンポジションに依存する処理にはエフェクト API を使います。
段階的な移行中は View と Compose を相互運用できるため、Compose を採用するために全面書き換えを行う必要はありません。
コメント
GitHub で閲覧・コメントする(投稿にはログインが必要です)