Androidアーキテクチャの階層構造
Androidオペレーティングシステムは、主に以下の4つの階層から構成されています。これらを理解することは、アプリ開発の基盤を把握する上で不可欠です。
- Linuxカーネル層: ハードウェア抽象化、セキュリティ、メモリ管理、プロセス管理などの基本機能を提供します。
- ライブラリおよびランタイム層: C/C++で記述されたライブラリ(SSL、SQLiteなど)と、Dalvik仮想マシン(またはART)を含みます。
- アプリケーションフレームワーク層: Activityマネージャーやロケーションマネージャーなど、アプリ開発者が利用するAPIの集合体です。
- アプリケーション層: ユーザーが実際に操作するメールクライアント、ブラウザ、カメラなどのアプリが配置されます。
アクティビティのライフサイクルと状態
Activityは、ユーザーインターフェースを持つ単一の画面を表します。そのライフサイクルはシステムによって管理され、以下のような状態遷移を辿ります。
- Active(アクティブ/実行中): 画面がフォアグラウンドにあり、ユーザー操作を受け付けられる状態。
- Paused(一時停止): 画面の一部が他のアクティビティ(ダイアログなど)によって隠されているが、まだ部分的に見えている状態。
- Stopped(停止): 画面が完全に別のアクティビティによって隠されており、ユーザーから見えない状態。インスタンスは保持されますが、ウィンドウは非表示です。
- Killed(破棄): Activityがシステムによってメモリから解放された状態。
Androidの4大コンポーネント
Androidアプリは、以下の4つの主要なコンポーネントの組み合わせによって構築されます。
Activity(アクティビティ)
UIを表示し、ユーザーとの対話を処理するエントリーポイントです。全画面、ダイアログ、浮遊ウィンドウなど、様々な形態で存在します。
Service(サービス)
UIを持たず、バックグラウンドで長時間実行される処理や、他のアプリケーションとの通信を担当します。
- Started Service:
startService()で起動。バックグラウンド処理を行い、処理完了またはstopService()呼び出しで終了します。 - Bound Service:
bindService()で起動。クライアントとサーバー(サービス)間のインターフェースを提供し、相互通信を可能にします。
Content Provider(コンテンツプロバイダ)
アプリ間でのデータ共有を管理します。ファイルシステム、SQLiteデータベース、Web上のデータなどを、他のアプリがContentResolverを通じてアクセスできるようにします。データアクセスのインターフェースを統一する役割を持ちます。
Broadcast Receiver(ブロードキャストレシーバ)
システム全体またはアプリ間で送信されるメッセージ(ブロードキャスト)を受信・応答するコンポーネントです。UIを持ちません。
- Normal Broadcast(通常ブロードキャスト): 非同期で送信され、すべてのレシーバがほぼ同時に受信します。効率的ですが、受信側が伝播を中断したり内容を変更したりすることはできません。
- Ordered Broadcast(順序付きブロードキャスト): 優先度に従って受信者が順次呼び出されます。受信者は結果を次の受信者に伝播させたり、ブロードキャストを中止したりすることが可能です。
Intent(インテント)による連携
Intentは、異なるコンポーネント間を実行時に結びつけるためのメッセージングオブジェクトです。主にアクティビティの起動、サービスの開始、ブロードキャストの送信、データの受け渡しに使用されます。
以下は、新しい画面を開き、データを渡す実装例です。
// Intentの生成とデータの追加
Intent transitionIntent = new Intent(SourceActivity.this, TargetActivity.class);
transitionIntent.putExtra("user_name", "Suzuki");
transitionIntent.putExtra("score", 95);
// 次のActivityの起動
startActivity(transitionIntent);
遷移先画面でデータを受け取るコードは以下のようになります。
Intent receivedData = getIntent();
String userName = receivedData.getStringExtra("user_name");
int userScore = receivedData.getIntExtra("score", 0);
主要なレイアウトと配置プロパティ
UIはレイアウトファイル(XML)で定義され、以下のような種類があります。
LinearLayout(リニアレイアウト)
ビューを単一の方向(垂直または水平)に整列させます。
android:orientation: "horizontal" または "vertical"。android:layout_weight: 余白の配分比率を指定。
RelativeLayout(相対レイアウト)
他のビューまたは親コンテナとの相対的な位置関係に基づいて配置します。
android:layout_centerInParent: 親の中央に配置。android:layout_toRightOf: 指定IDのビューの右側に配置。
FrameLayout(フレームレイアウト)
画面左上を原点として、ビューを重ねて配置します。Z軸方向のスタック管理に適しています。
GridLayout(グリッドレイアウト)
行列形式のグリッドにビューを配置します。1つのセルに1つのコンポーネントを配置し、rowSpanやcolumnSpanで複数セルにまたがることも可能です。
主要なUIコンポーネント
- TextView: テキスト表示。
android:autoLinkでURLや電話番号を自動リンク化。 - EditText: テキスト入力。
inputType属性で入力制限(パスワード、数値など)を設定。 - CheckBox / RadioButton: 選択インターフェース。RadioButtonはRadioGroup内で排他的に動作します。
- Fragment: Activity内の再利用可能なモジュール。UIの柔軟性と画面サイズへの対応(マルチペイン)を向上させます。
マルチスレッドとHandlerによるUI操作
AndroidのUI操作はメインスレッド(UIスレッド)で行う必要があります。時間のかかる処理を別スレッドで実行し、その結果をUIに反映させるためにHandlerを使用します。
private final ProgressBar progressView = findViewById(R.id.progress_bar);
// Handlerの定義(UIスレッドでMessageを処理)
private final UIHandler uiHandler = new UIHandler(this);
static class UIHandler extends Handler {
private final WeakReference<MainActivity> activityRef;
UIHandler(MainActivity activity) {
this.activityRef = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = activityRef.get();
if (activity != null) {
int currentProgress = msg.what;
activity.progressView.setProgress(currentProgress);
}
}
}
// 別スレッドでの処理
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
try {
Thread.sleep(50);
// メッセージ送信(値を渡す)
uiHandler.sendEmptyMessage(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
データの永続化
Androidアプリでは、以下の方法でデータを保存できます。
- SharedPreferences(プリファレンス): 設定情報など、軽量なキーバリューペアデータを保存するのに適しています。
- 内部ストレージファイル: アプリ専用の領域にファイルを保存します。他のアプリからはアクセスできません。
ファイル書き込みの実装例:
String fileName = "user_data.txt";
String content = "保存したいテキストデータ";
try (FileOutputStream outputStream = openFileOutput(fileName, Context.MODE_PRIVATE)) {
outputStream.write(content.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
JSONデータの解析
Web APIとの連携などでよく使用されるJSON形式のデータ解析は、JSONObjectおよびJSONArrayクラスを用いて行います。
String jsonString = "{\"team\": {\"name\": \"Engineering\", \"count\": 10}}";
try {
JSONObject rootObject = new JSONObject(jsonString);
JSONObject teamObject = rootObject.getJSONObject("team");
String teamName = teamObject.getString("name");
int memberCount = teamObject.getInt("count");
// データの使用
Log.d("JSONResult", "Team: " + teamName + ", Members: " + memberCount);
} catch (JSONException e) {
Log.e("JSONError", "Parsing failed", e);
}
リソース管理
コードから分離されたリソース(画像、文字列、色など)はresディレクトリ以下に配置します。
- res/values/colors.xml: 色定義。カラーコード(#RGB, #ARGBなど)で記述。
- res/values/strings.xml: 文字列定義。多言語対応や保守性を向上させるために必ず使用します。
- res/values/dimens.xml: サイズ定義。dp(密度非依存ピクセル)やsp(スケーラブルピクセル)を使用し、画面密度に応じたレイアウト調整を行います。
- res/drawable: 画像リソースやドロウアブルオブジェクト(XMLで定義する図形やセレクタなど)を配置します。