web-dev-qa-db-ja.com

電話がスリープ状態でもサービスを実行し続けますか?

アプリケーションに10分ごとに実行するように設計されたサービスがあります。基本的に、サーバーをチェックして、すべてが正常に実行されているかどうかを確認し、ユーザーに問題を通知します。このアプリケーションは、社内で使用するために作成しました。

私の同僚は、長い週末にアプリケーションを使用し、デバイスがスリープ状態になったときにチェックが実行されなかったことに気付きました。私は、コードでstopService()を明示的に呼び出すまで、サービスはバックグラウンドで実行し続けることになっているという印象を受けました。

最終的に、私の目標は、ユーザーがアプリケーションのオフボタンを押すか、プロセスを強制終了するまでサービスを実行することです。

画面がオフにならないようにするWakeLockと呼ばれるものについて聞きましたが、これは私が望んでいるものではありません。それからpartial WakeLockと呼ばれる別のことを聞きました。これは、デバイスがスリープ状態でもCPUを実行し続けます。後者は、私が必要としているものに近いように聞こえます。

このWakeLockを取得するにはどうすればよいですか?いつリリースする必要がありますか?

51
PaulG

注:この投稿は、Android LollipopリリースのJobScheduler AP​​Iを含むように更新されました。以下はまだ実行可能な方法ですが、ターゲットにしている場合は非推奨と見なすことができますAndroid Lollipop以降。JobSchedulerの代替については後半を参照してください。

繰り返しタスクを実行する1つの方法は次のとおりです。

  • クラスを作成するAlarmReceiver

    _public class AlarmReceiver extends BroadcastReceiver 
    {
        @Override
        public void onReceive(Context context, Intent intent) 
        {
            Intent myService = new Intent(context, YourService.class);
            context.startService(myService);
        }
    }
    _

    YourServiceがサービスです;-)

タスクにウェイクロックが必要な場合は、 WakefulBroadcastReceiver から拡張することをお勧めします。この場合、マニフェストに_WAKE_LOCK_パーミッションを追加することを忘れないでください!

  • 保留中のインテントを作成する

定期的なポーリングを開始するには、アクティビティで次のコードを実行します。

_Intent myAlarm = new Intent(getApplicationContext(), AlarmReceiver.class);
//myAlarm.putExtra("project_id", project_id); //Put Extra if needed
PendingIntent recurringAlarm = PendingIntent.getBroadcast(getApplicationContext(), 0, myAlarm, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarms = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
Calendar updateTime = Calendar.getInstance();
//updateTime.setWhatever(0);    //set time to start first occurence of alarm 
alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), AlarmManager.INTERVAL_DAY, recurringAlarm); //you can modify the interval of course
_

このコードは、alarmとキャンセル可能なpendingIntentをセットアップします。 alarmManagerは、recurringAlarmを毎日繰り返すジョブ(3番目の引数)を取得しますが、inexactので、CPUは間隔のほぼ後にウェイクアップしますが、正確ではありません(It OSが最適な時間を選択できるようにして、バッテリーの消耗を減らします。アラーム(したがってサービス)が最初に開始されるのは、updateTimeを選択したときです。

  • 最後になりましたが、繰り返しアラームを殺す方法は次のとおりです

    _Intent myAlarm = new Intent(getApplicationContext(), AlarmReceiver.class);
    //myAlarm.putExtra("project_id",project_id); //put the SAME extras
    PendingIntent recurringAlarm = PendingIntent.getBroadcast(getApplicationContext(), 0, myAlarm, PendingIntent.FLAG_CANCEL_CURRENT);
    AlarmManager alarms = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
    alarms.cancel(recurringAlarm);
    _

このコードは、(おそらく)既存のアラームのコピーを作成し、alarmManagerにその種類のすべてのアラームをキャンセルするよう指示します。

  • もちろん、Manifestにもやることがあります:

これらの2行を含める

_  < receiver Android:name=".AlarmReceiver"></receiver>
  < service Android:name=".YourService"></service>
_

_< application>_-タグ内。これがないと、システムはサービスの再発アラームの開始を受け入れません。


Android Lollipopリリース以降、このタスクをエレガントに解決する新しい方法があります。また、これにより、ネットワーク状態などの特定の基準が満たされた場合にのみアクションを実行しやすくなります。

_// wrap your stuff in a componentName
ComponentName mServiceComponent = new ComponentName(context, MyJobService.class);
// set up conditions for the job
JobInfo task = JobInfo.Builder(mJobId, mServiceComponent)
   .setPeriodic(mIntervalMillis)
   .setRequiresCharging(true) // default is "false"
   .setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED) // Parameter may be "ANY", "NONE" (=default) or "UNMETERED"
   .build();
// inform the system of the job
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(task);
_

setOverrideDeadline(maxExecutionDelayMillis)を使用して期限を指定することもできます。

このようなタスクを取り除くには、jobScheduler.cancel(mJobId);またはjobScheduler.cancelAll();を呼び出すだけです。

61
stefan

このアプリケーションを最初から構築してサーバー側コンポーネントを使用し(はい、監視も必要です!)、プッシュ通知を送信する場合、ポーリングは決して信頼できるソリューションではありません。

5
Lee Hambley

From Androidドーズモードでのドキュメントは次のようになります:( https://developer.Android.com/training/monitoring-device-state/doze-standby ):

_The system ignores wake locks._

_The system does not allow JobScheduler to run._

AndroidはsetAndAllowWhileIdle() or setExactAndAllowWhileIdle().にない限りAlarmManagerも無視します

_Network access is suspended._

したがって、唯一の方法は、setAndAllowWhileIdle()またはsetExactAndAllowWhileIdle()で高優先度のFCMまたはAlarmManagerを使用することです。

3
Saba