バックグラウンド タスクに関するシステムの制限

バックグラウンド プロセスは、メモリと電池を大量に消費することがあります。たとえば、暗黙的ブロードキャストにより、それをリッスンするように登録されているバックグラウンド プロセスが、作業量が少ないにもかかわらず多数開始される可能性があります。これは、デバイスのパフォーマンスとユーザー エクスペリエンスの両方に大きな影響を与える可能性があります。

システム制限を回避するには、バックグラウンド タスクに適切な API を使用してください。バックグラウンド タスクの概要のドキュメントは、ニーズに適した API を選択する際に役立ちます。

ユーザーが開始する制限

アプリが Android Vitals に記述されている不正な動作を行った場合、そのアプリによるシステム リソースへのアクセスを制限するように、システムがユーザーに求めます。

アプリが過度にリソースを消費していることをシステムが検知すると、ユーザーに通知され、ユーザーにアプリのアクションを制限するかどうかの確認が求められます。 このような通知のきっかけとなる動作には、次のようなものがあります。

  1. 過度な wake lock: 画面がオフのときに、1 つの部分的な wake lock が 1 時間保持されている
  2. 過剰なバックグラウンド サービス: 対象 API レベルが 26 未満で、バックグラウンド サービスが過剰である場合

詳細な制限はデバイス メーカーが決定します。たとえば、AOSP ビルドでは、制限されたアプリは、アプリがフォアグラウンドにある場合を除き、ジョブの実行、アラームのトリガー、ネットワークの使用ができません。

ネットワーク アクティビティのブロードキャストの受信に関する制限

アプリは、CONNECTIVITY_ACTION ブロードキャストを受信するようにマニフェストに登録しても受信せず、このブロードキャストに依存するプロセスは開始されません。これは、ネットワークの変更をリッスンする、またはデバイスが定額制のネットワークに接続したときに、まとめてネットワーク アクティビティを実行するアプリに問題を引き起こす可能性があります。この制限を回避する方法は、すでに Android フレームワークにいくつか存在しますが、どれを選択すべきかはアプリの目的によって異なります。

定額制の接続で実行するように処理をスケジューリングする

WorkRequest を作成するときに、NetworkType.UNMETERED Constraint を追加します。

fun scheduleWork(context: Context) {
    val workManager = WorkManager.getInstance(context)
    val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
        .setConstraints(
            Constraints.Builder()
                .setRequiredNetworkType(NetworkType.UNMETERED)
                .build()
        )
        .build()

    workManager.enqueue(workRequest)
}

処理の条件が満たされると、アプリはコールバックを受信して、指定された Worker クラスの doWork() メソッドを実行します。

アプリの実行中にネットワーク接続を監視する

実行中のアプリは、登録済みの BroadcastReceiver で CONNECTIVITY_CHANGE を引き続きリッスンできます。しかし、ConnectivityManager API は、指定されたネットワーク条件が満たされた場合にのみコールバックを要求する、より堅牢な手段を提供します。

NetworkRequest オブジェクトは、NetworkCapabilities に関するネットワーク コールバックのパラメータを定義します。NetworkRequest.Builder クラスを使用して NetworkRequest オブジェクトを作成します。作成後、registerNetworkCallback は NetworkRequest オブジェクトをシステムに渡します。ネットワーク条件が満たされると、アプリはコールバックを受信し、ConnectivityManager.NetworkCallback クラスで定義された onAvailable() メソッドを実行します。

アプリは、終了するか unregisterNetworkCallback() を呼び出すまで、コールバックを受信し続けます。

画像や動画のブロードキャストの受信に関する制限

アプリは ACTION_NEW_PICTURE ブロードキャストと ACTION_NEW_VIDEO ブロードキャストの送受信ができません。この制限は、新しい画像や動画を処理するために複数のアプリを復帰させる必要がある場合に、パフォーマンスとユーザー エクスペリエンスが低下するのを防ぎます。

作業をトリガーしたコンテンツ認証局を調べる

WorkerParameters を使用すると、どのコンテンツ認証局と URI がジョブをトリガーしたかに関する有用な情報を、アプリが受信できるようになります。

List<Uri> getTriggeredContentUris()

作業をトリガーした URI のリストを返します。ジョブをトリガーした URI がない場合(たとえば、デッドラインを超えたなどの理由でジョブがトリガーされた場合)、または変更された URI の数が 50 より多い場合は、空になります。

List<String> getTriggeredContentAuthorities()

処理をトリガーしたコンテンツ認証局を文字列のリストで返します。返されたリストが空でない場合は、getTriggeredContentUris() を使用して変更された URI の詳細を取得します。

次のサンプルコードは、CoroutineWorker.doWork() メソッドをオーバーライドし、ジョブをトリガーしたコンテンツ認証局と URI を記録します。

class MyWorker(
    appContext: Context,
    private val params: WorkerParameters
) : CoroutineWorker(appContext, params) {
    override suspend fun doWork(): Result {
        StringBuilder().apply {
            append("Media content has changed:\n")
            params.triggeredContentAuthorities
                .takeIf { it.isNotEmpty() }
                ?.let { authorities ->
                    append("Authorities: ${authorities.joinToString(", ")}\n")
                    append(params.triggeredContentUris.joinToString("\n"))
                } ?: append("(No content)")
            Log.i(TAG, toString())
        }
        return Result.success()
    }
}

システム制限下でアプリをテストする

アプリをメモリの少ないデバイスやメモリが少ない状態に最適化すると、パフォーマンスやユーザー エクスペリエンスが向上します。バックグラウンド サービスとマニフェストに登録された暗黙的ブロードキャスト レシーバの依存関係を削除すると、そのようなデバイスでのアプリの動作が改善されます。これらのバックグラウンド プロセスをまったく使用せずに動作するようにアプリを最適化することをおすすめします。

Android Debug Bridge(ADB)コマンドが追加され、バックグラウンド プロセスを無効にしてアプリの挙動をテストできるようになりました。

  • 暗黙的ブロードキャストとバックグラウンド サービスが使用できない状況をシミュレートするには、次のコマンドを入力します。

    $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore

  • 暗黙的ブロードキャストとバックグラウンド サービスを再度有効にするには、次のコマンドを入力します。

    $ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow

アプリをさらに最適化する

バックグラウンド タスクの動作を最適化するその他の方法については、タスク スケジューリング API のバッテリー使用量を最適化するをご覧ください。