web-dev-qa-db-ja.com

Android O-古い開始フォアグラウンドサービスはまだ機能していますか?

したがって、Android Oを使用すると、1時間に数回以上の位置情報の更新を受信する場合は、サービスをフォアグラウンドサービスとして実行する必要があります。

フォアグラウンドサービスを開始する古い方法は、Oで動作するように見えることに気付きました。

startForeground(NOTIFICATION_ID, getNotification());

ここの動作変更ガイドによると: https://developer.Android.com/preview/behavior-changes.html

NotificationManager.startServiceInForeground()メソッドは、フォアグラウンドサービスを開始します。フォアグラウンドサービスを開始する古い方法は機能しなくなりました。

新しい方法はOをターゲットとする場合にのみ機能しますが、Oをターゲットとするかどうかに関係なく、Oのデバイスでは古いメソッドがまだ機能しているようです。

Edit例を含む:

GoogleサンプルプロジェクトLocationUpdatesForegroundServiceには、実際に問題を直接確認できる実用的な例があります。 https://github.com/googlesamples/Android-play-location/tree/master/LocationUpdatesForegroundService

StartForegroundメソッドは、APIレベル25 ORをターゲットにしてコンパイルし、Oをターゲットにしてコンパイルしても問題なく動作するようです(こちらを参照してください: https://developer.Android.com/preview/ migration.html#uya

したがって、再現するには:

  1. 前のリンクで述べたようにアプリのグラドルを構成します
  2. アプリを開く
  3. 場所の更新をリクエストする
  4. アプリを閉じる(戻るボタンまたはホームボタンを使用)

サービスはフォアグラウンドで実行されています(通知シェードのアイコンで表示)。 Oを実行しているデバイスでも、位置情報の更新は予想どおり(10秒ごとに)行われます。

32
the_new_mr

これは私のために働いた。

  1. Activityクラスで、startService()の代わりにstartForegroundService()を使用してサービスを開始します
    Intent myService = new Intent(this, MyService.class);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForegroundService(myService);
    } else {
        startService(myService);
    }
  1. これで、サービスクラスのonStartCommand()で次のように実行します
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    ......
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

        Notification.Builder builder = new Notification.Builder(this, Android_CHANNEL_ID)
                .setContentTitle(getString(R.string.app_name))
                .setContentText(text)
                .setAutoCancel(true);

        Notification notification = builder.build();
        startForeground(1, notification);

    } else {

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setContentTitle(getString(R.string.app_name))
                .setContentText(text)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setAutoCancel(true);

        Notification notification = builder.build();

        startForeground(1, notification);
    }
    return START_NOT_STICKY;
}

注:NotificationCompat.Builderの代わりにNotification.Builderを使用すると機能しました。 Notification.Builderでのみ、Android Oreoの新機能であるチャンネルIDを提供する必要があります。

うまくいくことを願っています!

44
Bikram

アクティビティ(またはフォアグラウンドサービスを開始する任意のコンテキスト)で、これを呼び出します:

Intent intent = new Intent(this, MyService.class)
ContextCompat.startForegroundService(context, intent);

サービスが開始されたら、 Android docs say と同様のコードを使用して通知チャネルを作成し、ビルドを作成してこれを使って:

final Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID).setSmallIcon(...)//
            .setPriority(...).setCategory(...).setContentTitle(...).setContentText(...).setTicker(...);
// and maybe other preparations to the notification...
startForeground(notificationId, builder.build());
6

通常、startServiceを使用して、放送受信機からサービスを開始します。バックグラウンドの制限があるため、startServiceを呼び出すことはもはや不可能(または信頼性が高い)であるため、代わりにstartServiceInForegroundを呼び出す必要があります。ただし、ドキュメントからは、ブロードキャストインテントを受信するとアプリがホワイトリストに登録されるため、いつ発生するかは明確ではないため、startServiceIllegalStateExceptionをスローするタイミングは明確ではありません。

6
greywolf82

また、コメントで言及された@Kislingk NotificationManager.startServiceInForegroundは削除されました。 commit 08992ac で非推奨としてマークされました。

コミットメッセージから:

サービスを直接フォアグラウンド状態に開始するためにアプリオリ通知を提供する必要はなく、バックグラウンド実行状態からでも進行中のサービス作業を引き受けるために2段階の複合操作を採用します。 Context#startForegroundService()は、5秒以内にstartForeground()を介してサービスが正式にフォアグラウンド状態に入るという要件により、バックグラウンドの制限を受けません。サービスがそうしない場合、OSによって停止され、アプリはサービスANRで非難されます。

3
einsA

フォアグラウンドサービスを開始する従来の方法は、アプリがフォアグラウンドにある場合でも機能しますが、APIレベル26/Android Oを対象とするアプリのフォアグラウンドサービスを開始する推奨方法は、新しく導入されたNotificationManager#startServiceInForegroundメソッドを使用してフォアグラウンドサービスを作成することですそもそも。

Android Oのバックグラウンド実行制限のため、アプリがバックグラウンドモードの場合、バックグラウンドでサービスを開始してからフォアグラウンドにプロモートする古い方法は機能しません。

移行プロセスと手順はここに記載されています。 https://developer.Android.com/preview/features/background.html#migration

3
balendran

startForeground(1、notification); Android Oで機能しますが、Android O要件に従って、ユーザーに永続的な通知を表示する必要があります。同時に、場合によってはユーザーを混乱させる可能性があり(バックグラウンドで実行され、バッテリーに影響を与えるアプリに関するシステム通知)、ユーザーがアプリをアンインストールする可能性があります。したがって、WorkManagerクラスを新たに導入して、タスクをフォアグラウンドとしてスケジュールすることをお勧めします。

  1. 長時間実行されるタスクを実行できる「Worker」クラスを拡張して、ワーカークラス(MyWorkerなど)を作成します。このクラスの以下のメソッドをオーバーライドします:
    • doWork()[必須]
    • onStopped()[オプション]
    • onWorkFinished [オプション]など。
  2. 要件に従って、繰り返し/定期的な[PeriodicWorkRequest]または非繰り返しの[OneTimeWorkRequest]作業を作成します。
  3. WorkManagerのインスタンスを取得し、作業をキューに入れます。

コードスニペット:

OneTimeWorkRequest work =
     new OneTimeWorkRequest.Builder(MyWorker.class)
 .build();
WorkManager.getInstance().enqueue(work);    
0
Akki

バックスタックビルダーで必要な場合はサンプルを追加します

    val notifyManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
    val playIntent    = Intent(this, this::class.Java).setAction(PAUSE)
    val cancelIntent  = Intent(this, this::class.Java).setAction(EXIT)

    val stop          = PendingIntent.getService(this, 1, playIntent, PendingIntent.FLAG_UPDATE_CURRENT)
    val exit          = PendingIntent.getService(this, 2, cancelIntent, PendingIntent.FLAG_UPDATE_CURRENT)

    val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        notifyManager.createNotificationChannel(NotificationChannel(NOTIFICATION_ID_CHANNEL_ID, getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH))
        NotificationCompat.Builder(this, NOTIFICATION_ID_CHANNEL_ID)
    } else
        NotificationCompat.Builder(this)

    builder.apply {
        setContentTitle(station.name)
        setContentText(metaToText(meta) )
        setSmallIcon(R.drawable.ic_play_arrow_white_24px)
        setAutoCancel(false)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) priority = Notification.PRIORITY_MAX
        addAction(R.drawable.ic_stop_white_24px, getString(R.string.player_notification_stop), stop)
        addAction(R.drawable.ic_close_white_24px, getString(R.string.player_notification_exit), exit)
    }

    val stackBuilder = TaskStackBuilder.create(this)
    stackBuilder.addParentStack(PlayerActivity::class.Java)
    stackBuilder.addNextIntent(Intent(this, PlayerActivity::class.Java))
    builder.setContentIntent(stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT))

    startForeground(NOTIFICATION_ID, builder.build())
0
pavol.franek