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

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

システムの制限を回避するには、バックグラウンド タスクに適した 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() メソッドを実行します。

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

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

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

アプリは、終了するか 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,
    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 のバッテリー使用量を最適化する をご覧ください。