私は現在、オーディオ再生アプリに取り組んでおり、開始されたバインドされたサービスを使用してバックグラウンドで音楽を再生しています。次のコードを使用して、サービスを開始してバインドします。
val intent = Intent(context, MusicService::class.Java)
context.startService(intent)
context.bindService(intent, serviceConnection, 0)
再生時にフォアグラウンドに昇格し、音楽が一時停止すると降格します。
// onAudioPlay
service.startForeground(NOTIFY_ID, notification)
// onAudioPause
service.stopForeground(false)
これまでのサービス作業は問題ありません。ただし、一時停止状態のユーザーが通知をスワイプ(削除)すると、このエラーが発生して数秒後にサービスがクラッシュします。
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myplayer, PID: 4380
Android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1775)
Android.os.Handler.dispatchMessage(Handler.Java:105)
Android.os.Looper.loop(Looper.Java:164)
Android.app.ActivityThread.main(ActivityThread.Java:6541)
Java.lang.reflect.Method.invoke(Native Method)
com.Android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.Java:240)
com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:767)
これはOreoでのみ発生し、Oreoのバックグラウンドの制限についてはすでに読んでいます。しかし、次の点は私を悩ませます。
サービスがクラッシュするのはなぜですか?私は何を間違えていますか?ここで起こっていることを誰かが教えてくれてとても感謝しています。
deshUk's answer -を展開すると、MediaButtonReceiver
(保留中のインテントを作成するか、メディアボタンインテントを受信する)を使用すると、MediaButtonReceiver.onReceive
がOreoでそのようにサービスを開始するため、startForegroundService
でサービスが呼び出されます。これはどこにも記録されていません。
ServiceクラスのonCreate()メソッド内でこのメソッドを呼び出す必要があります:->
private void startServiceOreoCondition(){
if (Build.VERSION.SDK_INT >= 26) {
String CHANNEL_ID = "my_service";
String CHANNEL_NAME = "My Background Service";
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
CHANNEL_NAME,NotificationManager.IMPORTANCE_NONE);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setCategory(Notification.CATEGORY_SERVICE).setSmallIcon(R.drawable.ic_tgc_icon).setPriority(PRIORITY_MIN).build();
startForeground(101, notification);
}
}
問題が見つかりました。私の通知で私は設定しました
setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(service, PlaybackStateCompat.ACTION_STOP))
したがって、ユーザーが通知を削除すると、一時停止時に以前にstopForeground()を呼び出したため、startForegroundService()が呼び出されます。
克服するために、カスタム保留インテントを使用し、MediaButtonReveiver's PendingIntentの代わりにonStartCommand()
で処理しました
ドキュメントから 8.0動作の変更
システムは、アプリがバックグラウンドにあるときでも、アプリがContext.startForegroundService()を呼び出すことを許可します。ただし、アプリは、サービスの作成後5秒以内にそのサービスのstartForeground()メソッドを呼び出す必要があります。
したがって、サービスのonCreate()内でstartForegroundを呼び出す必要があります。
パーティーに遅れましたが、前述のとおり、それはMediaButtonReceiver
です。このコードがあります:
@Override
public void onReceive(Context context, Intent intent) {
...
startForegroundService(context, intent);
...
}
バインドされたサービスでレシーバーを使用しているため、この行を除き、MediaButtonReceiver
とまったく同じコードを持つクラスを作成しました。私はそれを次のものに置き換えました:
context.startService(intent);