onStartは、ActivityまたはFragmentがユーザーに表示される際に呼び出されるAndroidライフサイクルメソッドです。この瞬間、画面がデバイスのディスプレイに表示されますが、onResumeが呼び出されるまで入力フォーカスがなく、まだユーザーと対話できません。onStartメソッドは、システムリスナーの登録、位置情報サービスへの接続、コンポーネントが画面に表示されている間動作するアニメーションの開始に最適です。完全なActivityライフサイクルの詳細については、記事Activity Lifecycleをご覧ください。
重要なポイント
onStartはActivityライフサイクルの2番目のメソッドであり、システムによってonCreateの後(または停止状態から戻る場合はonRestartの後)に呼び出されます。onStartが呼び出された瞬間、ActivityまたはFragmentが画面に表示されます。ユーザーはインターフェースを表示できますが、画面はまだ対話の準備ができていません — 入力フォーカスはonResumeの後にのみ表示されます。
onStartメソッドはActivityの「可視ライフタイム」(visible lifetime) — onStartとonStopの間の期間に含まれます。この間、Activityは他のウィンドウ(透明なActivityやダイアログウィンドウなど)で部分的に覆われることがありますが、UIは引き続き表示されたままです。これは、Activityが完全な入力フォーカスを持つ「フォアグラウンドライフタイム」(onResume — onPause)とは異なります。
この3レベルの階層を理解することは、コードを適切に分散するために重要です。onCreate — 1回限りの初期化、onStart — 可視リソースの接続、onResume — 排他的リソースへの排他的アクセス。これらのレベルを混同する開発者は、画面切り替え時にメモリリークやアプリケーションの誤動作を引き起こすリスクがあります。
Activityでは、画面がディスプレイに表示されるたびにonStartメソッドが呼び出されます — 最初の起動時(onCreate後)とバックグラウンドから戻る時(onRestart後)の両方です。onCreateとは異なり、onStartはActivityインスタンスの生存期間中に複数回呼び出される可能性があるため、画面が表示されるたびに実行する必要があるコードがここに配置されます。
class DashboardActivity : AppCompatActivity() {
private val connectivityReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val isConnected = ... // ConnectivityManagerの確認
binding?.statusIndicator?.setColor(
if (isConnected) Color.GREEN else Color.RED
)
}
}
override fun onStart() {
super.onStart()
registerReceiver(
connectivityReceiver,
IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
)
SensorManager.getInstance().registerStepCounter()
}
override fun onStop() {
unregisterReceiver(connectivityReceiver)
SensorManager.getInstance().unregisterStepCounter()
super.onStop()
}
}
重要なルール:onStartで接続したすべてのリソースはonStopで解放する必要があります。これにより、Activityが画面から非表示になったときに、バッテリーを消費したり、システムイベントをリッスンしたり、メモリを占有したりしなくなります。Android Studioには、対応する登録解除なしでBroadcastReceiverを登録することを警告するlintルールが含まれています。
FragmentのonStartは、ホストActivityのライフサイクルに密接に関連しています。Fragmentは、それを含むActivityがonStartを受け取った後にonStartを受け取ります。ただし、Fragmentが遅延モード(addToBackStackなしのFragmentTransaction.commit())で追加された場合、onStartは遅延して呼び出されることがあります。
class MapFragment : Fragment() {
private var mapView: MapView? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
mapView = MapView(requireContext())
return mapView!!
}
override fun onStart() {
super.onStart()
mapView?.onStart()
LocationService.connect(requireContext())
}
override fun onStop() {
mapView?.onStop()
LocationService.disconnect()
super.onStop()
}
}
Fragment.onStartの特殊性:FragmentがoffscreenPageLimit = 1のViewPager内にある場合、隣接するフラグメントも表示される前にonStartを受け取ります。これにより、リスナーが早期に登録される可能性があります。このような場合は、setUserVisibleHint()メソッドを使用するか、onStart内でisVisibleをチェックして、実際に表示されているフラグメントに対してのみリスナーを登録します。
onStartとonResumeの主な違いは、画面アクティビティのレベルです。onStartはActivityが画面に表示されているが、必ずしもフォアグラウンドにあるわけではないことを示します。onResumeはActivityがフォアグラウンドにあり、入力フォーカスを持っていることを示します。この違いはダイアログウィンドウの例で示されます。Activityの上にDialogが表示されると、ActivityはonResumeを失います(onPauseが呼び出されます)が、表示されたままになります — onStart/onStopは呼び出されません。
比較表は、各メソッドがどのシナリオで呼び出されるかを明確に示しています:
| シナリオ | onStart | onResume |
|---|---|---|
| アプリ起動 | 呼び出される | 呼び出される |
| Activity上にDialogが開かれる | 呼び出されない | onPause(フォーカス喪失) |
| ホームボタンが押される | onStop(非表示) | onPause → onStop |
| 最近のアプリから戻る | onStart(表示) | onResume(フォーカス) |
| 画面回転 | onCreate → onStart | → onResume |
| 着信 | onStop(非表示) | onPause → onStop |
この表は、開発者が特定のコードをどのメソッドに配置するかを決定するのに役立ちます。たとえば、アプリが画面のオーバーラップ(ダイアログでも)の際にビデオ再生を一時停止する必要がある場合、コードはonPauseに配置されます。画面が完全に非表示になったときにのみビデオを停止する必要がある場合 — コードはonStopに配置されます。
onStartは、Activityが画面に表示されている間のみ動作するリスナーを登録するための最適な場所です。これは、システムイベント用のBroadcastReceiver、位置情報用のLocationListener、デバイスセンサー用のSensorListenerの3つの主要なシステムコンポーネントに関係します。
BroadcastReceiverはonStartでContext.registerReceiver()を介して動的に登録され、onStopでunregisterReceiver()を介して登録解除されます。動的登録は、マニフェストでの静的登録よりも推奨されます。これは、レシーバーのライフタイムをActivityの可視期間に制限するためです — Activityが非表示の場合、アプリはシステムブロードキャストメッセージで起動しません。
private val batteryReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
binding?.batteryText?.text = "$level%"
}
}
override fun onStart() {
super.onStart()
registerReceiver(batteryReceiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
}
override fun onStop() {
unregisterReceiver(batteryReceiver)
super.onStop()
}
位置情報とセンサーはリソースを大量に消費する操作です。onStartでGPS更新を要求し、onStopでキャンセルすることで、画面が非表示のときにアプリがバッテリーを消費しないようにします。細かい調整には、最小間隔と距離を指定したrequestLocationUpdatesを使用します — たとえば、10秒と10メートル。これにより、精度と消費電力の最適なバランスが得られます。
onCreateではなくonStartでアニメーションを開始することで、画面が表示されるたびにアニメーションが開始されます。onCreateでアニメーションを開始すると、最初のActivity作成時のみ機能し、バックグラウンドから戻る時には機能しません。onStartはActivityが表示されるたびに呼び出されるため、循環アニメーションやトランジションを開始するのに最適な場所です。
private lateinit var pulseAnimator: ValueAnimator
override fun onStart() {
super.onStart()
pulseAnimator.start()
binding?.loadingIndicator?.animate()?.alpha(1f)?.start()
}
override fun onStop() {
pulseAnimator.cancel()
binding?.loadingIndicator?.animate()?.cancel()
super.onStop()
}
ObjectAnimatorやValueAnimatorを使用するアニメーションでは、onStopでcancel()を呼び出すことが重要です。Activityが非表示になった後もアニメーションが実行され続けると、GPUとCPUのリソースを無駄に消費し、デバイスのパフォーマンスを低下させ、バッテリー消費を加速させます。Android Studio Profiler(GPUグラフ)を使用すると、アクティブなアニメーションを追跡し、リークを検出できます。
onStart/onStopのペアルールは、プレビュー用カメラ(CameraX)の操作にも適用されます。onStartでカメラを開き、onStopで閉じることで、アプリが画面に表示されていないときに他のアプリがカメラをブロックされないようにします。このルールの違反は、Google Playでネガティブなレビューの一般的な原因です。
よくある質問
onStart — 画面が表示されている間動作するリスナー用(BroadcastReceiver、LocationListener、SensorListener)。onResume — 排他的アクセスが必要なリソース用(カメラ、ビデオキャプチャ、音声認識)。システムイベントリスナーは排他的アクセスを必要とせず、部分的なオーバーラップでも動作できるため、onStartで登録されます。カメラは完全なフォーカスがある場合にのみアクティブにする必要があるため、onResumeで開かれます。
Activityが表示状態に移行する場合、onStartは常に呼び出されます。onStartなしの唯一のシナリオは、Activityが作成されてすぐに終了する場合です(たとえば、onCreateのエラーが原因)。この場合、onCreateの直後にonDestroyが呼び出されます。しかし、これは緊急シナリオであり、適切に記述されたコードでは発生するべきではありません。
はい、別のActivityまたは透明なウィンドウがActivityの上にすぐに開かれる場合、onStartはonResumeを受け取らないことがあります。たとえば、onCreateの後に認証画面が起動された場合(Activity A → Activity B)、Activity AではonStartが呼び出されますが、onResumeは呼び出されません — 画面Bに覆われるとすぐにonPause → onStopを受け取ります。
onStartはActivityインスタンスの生存期間中に複数回呼び出される可能性があります。Activityが非表示状態(onStop)から表示状態に移行するたびに、onStartが呼び出されます。実際には、アプリを積極的に使用すると、onStartはセッション中に数十回または数百回呼び出されることがあります。
onStartでのデータロードは、画面が表示されるたびにデータを更新する必要がある場合に正当化されます。たとえば、ニュースフィードや通知リストなどです。ただし、ロードは非同期で行う必要があります — lifecycleScopeを使用したコルーチンを介して、UIスレッドをブロックしないようにします。画面表示の間で変更されないデータの場合は、onCreateで1回ロードするだけで十分です。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。