タイトル: アクティビティ (Android アプリケーション)
SEOタイトル: Android Activity ライフサイクル完全解説 — onCreate/onPause/Intent/Backstack
| この記事の要点 |
|
Activity とは
Activity は Android アプリにおける「1 つの画面」を表す中心クラスです。ユーザーが見る UI の入り口でもあり、ライフサイクル管理・画面遷移・状態保存の起点となります。アプリは複数の Activity から構成され、それぞれが独立したスタックエントリとして遷移します。
近年はSingle Activity 構成(Activity 1 個 + Fragment / Jetpack Compose Navigation)が主流ですが、Activity の役割を理解しないと深い設計はできません。
最小の Activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<Button>(R.id.btn_next).setOnClickListener {
val intent = Intent(this, DetailActivity::class.java)
intent.putExtra("user_id", 42)
startActivity(intent)
}
}
}
// AndroidManifest.xml には登録必須
// <activity android:name=".MainActivity" android:exported="true">
// <intent-filter>
// <action android:name="android.intent.action.MAIN" />
// <category android:name="android.intent.category.LAUNCHER" />
// </intent-filter>
// </activity>
ライフサイクル
Activity は OS の状態に応じて、決まったコールバックが順番に呼ばれます。これがライフサイクルです。
| メソッド | 呼ばれるタイミング | 典型処理 |
|---|---|---|
onCreate | 初回生成(Activity 作成) | レイアウト設定、初期化 |
onStart | 画面が見える直前 | UI 更新の準備 |
onResume | フォアグラウンドで操作可能になる直前 | センサー / カメラ ON |
onPause | 別画面で半分隠れる直前 | センサー / カメラ OFF、軽い保存 |
onStop | 完全に見えなくなった | ヘビーな処理停止、DB に保存 |
onSaveInstanceState | onPause/onStop 直前 | 状態を Bundle に保存(画面回転対策) |
onRestart | onStop → 復帰 | 必要に応じて再開 |
onDestroy | Activity 破棄前 | リスナー解除、リソース解放 |
class DetailActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)
val userId = intent.getIntExtra("user_id", -1)
Log.d("Lifecycle", "onCreate userId=$userId")
}
override fun onStart() { super.onStart(); Log.d("Lifecycle", "onStart") }
override fun onResume() { super.onResume(); Log.d("Lifecycle", "onResume") }
override fun onPause() { super.onPause(); Log.d("Lifecycle", "onPause") }
override fun onStop() { super.onStop(); Log.d("Lifecycle", "onStop") }
override fun onDestroy() { super.onDestroy(); Log.d("Lifecycle", "onDestroy") }
override fun onSaveInstanceState(out: Bundle) {
out.putString("draft", editText.text.toString())
super.onSaveInstanceState(out)
}
}
Intent と Bundle でデータ受け渡し
// 送信側
val intent = Intent(this, DetailActivity::class.java).apply {
putExtra("user_id", 42)
putExtra("name", "Taro")
putExtra("is_admin", true)
}
startActivity(intent)
// 受信側 (DetailActivity.onCreate)
val userId = intent.getIntExtra("user_id", -1)
val name = intent.getStringExtra("name") ?: "Unknown"
val isAdmin = intent.getBooleanExtra("is_admin", false)
// Parcelable / Serializable も渡せるが、Activity 間で大量データはやめる
// 推奨は ViewModel 共有 (Single Activity 構成) or DB / SharedPreferences 経由
結果を受け取る (Activity Result API)
startActivityForResult は API レベル 31 で廃止。代替として Activity Result API を使います。
// 旧 (廃止)
// startActivityForResult(intent, REQUEST_CODE_PICK)
// → onActivityResult(requestCode, resultCode, data)
// 新: registerForActivityResult
class MainActivity : AppCompatActivity() {
private val pickContactLauncher = registerForActivityResult(
ActivityResultContracts.PickContact()
) { uri: Uri? ->
uri?.let { Log.d("Pick", "Selected $it") }
}
private val cameraLauncher = registerForActivityResult(
ActivityResultContracts.TakePicturePreview()
) { bitmap: Bitmap? ->
bitmap?.let { imageView.setImageBitmap(it) }
}
fun openPicker() {
pickContactLauncher.launch(null)
}
fun openCamera() {
cameraLauncher.launch(null)
}
}
Tasks と Back Stack
Activity はタスク (Task) という後入れ先出しスタックに積まれます。「戻る」ボタンでスタックから pop されます。
| launchMode | 挙動 | 用途 |
|---|---|---|
standard (デフォルト) | 毎回新規生成しスタックに積む | 通常画面 |
singleTop | スタック頂上が同一なら新規生成しない(onNewIntent) | 通知 → 既存画面 |
singleTask | タスク内で 1 つ。既存 Instance に戻り、上に積まれたものを破棄 | メイン / ホーム画面 |
singleInstance | 専用タスク。常に 1 個 | 通話 / アラーム画面 |
<!-- AndroidManifest.xml -->
<activity
android:name=".MainActivity"
android:launchMode="singleTop" />
<!-- 通知タップ → 既存 MainActivity を再利用、onNewIntent が呼ばれる -->
Jetpack Compose / Fragment との関係
モダンな構成では Activity を多用しません。
- Single Activity + Fragment + Navigation Component — 画面遷移を Fragment に委譲
- Single Activity + Jetpack Compose + Navigation — 画面遷移を Composable に委譲(最新主流)
- 複数 Activity — レガシー or プロセス分離が必要な場合のみ
// Compose Navigation で「画面遷移」を Activity 無しで実現
@Composable
fun AppNav() {
val nav = rememberNavController()
NavHost(nav, startDestination = "list") {
composable("list") { ListScreen(onClick = { id -> nav.navigate("detail/$id") }) }
composable("detail/{id}") { backStackEntry ->
DetailScreen(id = backStackEntry.arguments?.getString("id"))
}
}
}
FAQ
Q: 画面回転でデータが消える
A: onSaveInstanceState で Bundle に保存、または ViewModel に持たせる(Configuration Change を超えて生存)。
Q: finish() と onBackPressed() の違い
A: finish は明示的に閉じる(戻るボタンを押した相当)、onBackPressed は戻るボタン押下時のフック。OnBackPressedDispatcher を使うのが推奨。
Q: Single Activity 構成のメリット
A: 画面間のデータ共有が容易(ViewModel スコープ)、Animations が滑らか、メモリ効率良好、Compose との相性◎。