web-dev-qa-db-ja.com

実行時例外Android O with boot_completed

BOOT_COMPLETEDレシーバー内でIntentServiceを開始しようとしていますが、Android O(API 26)で次のようになります:

Java.lang.RuntimeException: 
Java.lang.IllegalStateException: 
Not allowed to start service Intent { act=intent.action.update cmp=packageName.services.OwnService }: 
app is in background

(メッセージは1行ですが、この方法で読みやすくなります)

これを正しい方法で行うにはどうすればよいですか?

28
mars3142

ブログ投稿 で説明したいくつかのオプションを次に示します。

回避策#1:startForegroundService()

_ACTION_BOOT_COMPLETED_ブロードキャストを受信するBroadcastReceiverは、Android 8.0+の場合、startForegroundService()の代わりにstartService()を呼び出すことができます。

_import Android.content.BroadcastReceiver;
import Android.content.Context;
import Android.content.Intent;
import Android.os.Build;

public class OnBootReceiver extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
    Intent i=new Intent(context, TestIntentService.class);

    if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O) {
      context.startForegroundService(i);
    }
    else {
      context.startService(i);
    }
  }
}
_

サービスが実際にstartForeground()を呼び出さなくても、これはある程度機能することに注意してください。 「これを行うためのANR間隔に相当する」startForeground()を呼び出すための時間枠が与えられます。作業が1ミリ秒より長く、数秒より短い場合、NotificationおよびstartForeground()呼び出しをスキップできます。ただし、LogCatでエラーが発生します。

_E/AndroidRuntime: FATAL EXCEPTION: main
 Process: com.commonsware.myapplication, PID: 5991
 Android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
     at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1775)
     at Android.os.Handler.dispatchMessage(Handler.Java:105)
     at Android.os.Looper.loop(Looper.Java:164)
     at Android.app.ActivityThread.main(ActivityThread.Java:6541)
     at Java.lang.reflect.Method.invoke(Native Method)
     at com.Android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.Java:240)
     at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:767)
_

もちろん、Notificationを短くすることを気にしない場合は、Androidが期待するとおりにstartForeground()を使用することを歓迎します。この場合、バックグラウンドで作業を行うことができます通常、ユーザーの通知シェードに表示されるエントリはありますが。

回避策#2:goAsync()

BroadcastReceiverはAPIレベル11以降goAsync()を提供しています。これにより、レシーバーはメインアプリケーションスレッドから作業を行うことができるため、IntentServiceを完全に削除し、 BroadcastReceiverにコード化します。 ANRタイムアウト期間はまだ残っていますが、メインアプリケーションスレッドを拘束することはありません。これは、同じ時間制限があるが厄介なエラーを回避する限り、最初の回避策よりも優れています。ただし、ある程度の手直しが必要です。

回避策#3:JobScheduler

作業に数秒以上かかる場合andNotificationを避けたい場合は、コードを修正してJobServiceを実装し、JobScheduler。これには、他の条件が満たされた場合にのみ制御できるという利点があります(たとえば、使用可能なインターネット接続がある)。ただし、これには書き換えが必要なだけでなく、JobSchedulerはAndroid 5.0+でのみ使用できるため、minSdkVersionが21未満の場合は、他の古いデバイスでのソリューション。

[〜#〜] update [〜#〜]:Eugen Pechanec 指摘JobIntentService 、これは興味深いJobService/IntentServiceマッシュアップ。

52
CommonsWare

Android O動作の変更に関するドキュメント https://developer.Android.com/preview/features/background.html#services の次のセクションを確認してください。

アプリがバックグラウンドサービスを開始できるタイミングが制限されるようになりました。

1
Ryan