Androidアプリウィジェットを使用しています。PendingIntent
オブジェクトを作成し、メソッドRemoteViews#setOnClickPendingIntent()
で使用しています。
// The below code is called in the onUpdate(Context, AppWidgetManager, int[]) method of the AppWidgetProvider class.
// Explicit intent
Intent intent = new Intent(context, MyService.class);
intent.setAction(MY_ACTION);
intent.putExtra(EXTRA_KEY, VALUE);
// Create the pending intent
PendingIntent pendingIntent = PendingIntent.getService(context, appWidgetId, intent, 0);
// 'views' is a RemoteViews object provided by onUpdate in the AppWidgetProvider class.
views.setOnClickPendingIntent(R.id.root_layout, pendingIntent);
上記のコードは、Android Oreoの前に期待どおりに動作します。ただし、Android Oreoでは、アプリが最近のPendingIntent
sはOreoのバックグラウンド実行制限から除外されていませんか?
テスト目的で、getService
をgetForegroundService
に置き換えましたが、Service
はまだ開始されていません。どちらの方法でも、ログに次のメッセージが表示されます。
W/ActivityManager: Background start not allowed: service Intent { act=com.example.myapp.MY_ACTION flg=0x10000000 cmp=com.example.myapp/com.example.myapp.MyService bnds=[607,716][833,942] (has extras) } to com.example.myapp/com.example.myapp.MyService from pid=-1 uid=10105 pkg=com.example.myapp
Service
を使用している場合でも、getForegroundService
が開始されないのはなぜですか? Android 8.1.0を実行しているNexus 6Pでこれをテストしました。
ご指摘のとおり、アプリウィジェットはPendingIntent
バックグラウンドホワイトリストにはカウントされません。理由はわかりませんが、PendingIntent
で始まるNotification
とほぼ同等のようです。おそらく、Notification
がシステムのものであるのに対して、アプリウィジェットはホーム画面のものであるという問題があります。ともかく:
getForegroundService()
を使用するか、または
Intent
を上げたくない場合は、明示的なBroadcastReceiver
を使用してgetBroadcast()
を試し、JobIntentService
を開始してNotification
を試してください。 (フォアグラウンドサービスに必要)
あなたの症状に基づいて、あなたは私がバグだと思うものをつまずいたように見えます:再起動することなくgetService()
からgetForegroundService()
に切り替える方法があるはずです。 :-)いくつかの実験を実行しようとしますが、問題を再現できる場合は問題を報告します。
8.0ではバックグラウンドでサービスを開始できなくなりましたが、JobScheduler
を使用して同様の結果を得ることができます。 JobIntentService
ヘルパークラスもあります。これにより、サービスを大幅に変更することなくJobScheduler
に切り替えることができます。また、サービスを指すPendingIntent
は使用できませんが、Activity
またはBroadcastReceiver
を指すものは使用できます。
8.0より前に動作するウィジェットがあり、Android 8.0で動作するようにする必要がある場合、次の簡単な手順を実行します。
IntentService
クラスをJobIntentService
に変更しますonHandleIntent
メソッドの名前をonHandleWork
に変更します(同じパラメーター)BIND_JOB_SERVICE
マニフェスト内のサービスに対する許可: <service Android:name=".widget.MyWidgetService"
Android:permission="Android.permission.BIND_JOB_SERVICE">
</service>
enqueueWork
静的メソッドを使用します(JOB_IDは単なる一意の整数定数であり、同じクラスのキューに入れられたすべての作業で同じ値でなければなりません): enqueueWork(context, MyWidgetService.class, JOB_ID, intent);
Intent myIntent = new Intent(context, MyAppWidgetProvider.class);
myIntent .setAction("SOME_UNIQUE_ACTION");
pendingIntent = PendingIntent.getBroadcast(context, 0, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent
がactivity
を開始していた場合は、そのままにしておきます-Android 8.0+ ): @Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if (intent.getAction().equals("SOME_UNIQUE_ACTION")) {
MyWidgetService.enqueueWork(.....);
}
}
widget
が古いデバイスで動作することを確認するには、マニフェストにWAKE_LOCK権限があることを確認してください(古いデバイスのJobIntentService
で使用)。それでおしまい。このウィジェットは、新しいデバイスと古いデバイスの両方で正常に機能するようになりました。唯一の本当の違いは、8.0デバイスが居眠りモードの場合、ウィジェットをそれほど頻繁に更新しない可能性があることですが、居眠りしている場合はユーザーがすぐにウィジェットを表示できないことを意味するため、問題にはなりませんいずれかの方法。
Goasycをオプションにできますか? PendingIntentを変更してBroadcastReceiverを起動し、OnRecieveメソッドでgoasync()を呼び出すことができます。次に、生成されるPendingResultを使用して非同期呼び出しを作成できるようになります。それでもサービスを開始できるとは思わないでください。