Работать ли сервис, даже когда телефон спит? - PullRequest
51 голосов
/ 03 января 2012

В моем приложении есть служба, которая запускается каждые 10 минут. Он в основном проверяет наши серверы, чтобы убедиться, что все работает правильно, и уведомляет пользователя о любых проблемах. Я создал это приложение для внутреннего использования в нашей компании.

Мой коллега использовал приложение в течение долгих выходных и заметил, что при переходе устройства в спящий режим проверки не выполнялись. У меня сложилось впечатление, что Служба должна была работать в фоновом режиме, пока я явно не вызову stopService() в своем коде.

Так что, в конечном счете, моя цель - запустить службу, пока пользователь не нажмет кнопку выключения в приложении или не завершит процесс.

Я слышал о чем-то, что называется WakeLock, которое предназначено для предотвращения выключения экрана, а это не то, чего я хочу. Затем я услышал о другом, называемом частичный WakeLock , который поддерживает работу процессора, даже когда устройство спит. Последнее звучит ближе к тому, что мне нужно.

Как мне приобрести этот WakeLock и когда мне его выпустить, и есть ли другие способы обойти это?

Ответы [ 3 ]

61 голосов
/ 03 января 2012

Примечание. Это сообщение было обновлено и теперь включает JobScheduler API выпуска Android Lollipop.Следующее является все еще жизнеспособным способом, но может считаться устаревшим, если вы ориентируетесь на Android Lollipop и выше.См. Вторую половину альтернативы JobScheduler.

Один из способов выполнения текущих задач заключается в следующем:

  • Создание класса 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 каждый день (третий аргумент), но неточно , поэтому ЦП действительно просыпается примерно после интервала, но не совсем (Это позволяет ОС выбирать оптимальное время, что уменьшает разрядку аккумулятора).Первый раз, когда сигнал тревоги (и, следовательно, служба) запускается, будет временем, которое вы выберете, чтобы быть 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:

, включив эти две строки

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

внутри < application> -tag.Без этого система не принимает начало периодической тревоги службы.


Начиная с версии 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();.

5 голосов
/ 03 января 2012

Я бы порекомендовал, если при создании этого приложения с самого начала использовать серверный компонент (да, также потребуется мониторинг!) И отправлять push-уведомления, опрос никогда не будет надежным решением.

3 голосов
/ 14 августа 2018

Из документации 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 также игнорирует AlarmManager, если только они не находятся в setAndAllowWhileIdle() or setExactAndAllowWhileIdle().

Network access is suspended.

Таким образом, единственный способ - использовать FCM с высоким приоритетом или AlarmManager с помощью setAndAllowWhileIdle () или setExactAndAllowWhileIdle ().

...