ForgroundService зависит от режима ожидания

Мое приложение будильника продолжает опаздывать, хотя я запускаю ForegroundService из BroadcastReceiver и onCreate() из Service gehts, вызванных вовремя, но onStartCommand() вызывается с задержкой (иногда), что, как я предполагаю, исходящий от телефона, который снова впадает в сон, прежде чем он может его выполнить ...

Как вы можете видеть из Log.d, служба запускается вовремя и вовремя вызывает PlayerActivity, но в этом случае на самом деле она запускается на 1:40 мин позже. Кроме того, Служба не выходит на передний план и не запускает потоковую передачу музыки до того, как истечет это случайное время задержки (окно обслуживания?)

Как мы должны держать устройство в бодрствующем состоянии достаточно долго, чтобы фактически запустить службу переднего плана и вовремя ВЫХОДИТЬ НА ПЕРЕДНИЙ ПЛАН?

Я использую setExactAndAllowWhileIdle() для вызова AlarmReceiver - это отлично работает в 100% случаев. Задержка происходит после запуска службы.

Должен ли я запускать службу на 15 минут раньше, чтобы убедиться, что она вышла на передний план к фактическому времени будильника и фактически начать потоковую передачу музыки и вызывать действие в действительное время будильника?

BroadcastReceiver

public class AlarmReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {

    Log.d("Ben", "Alarmreceiver HELLO");

    String label = context.getText(R.string.defaultLabel).toString();
    int id = 1909;

    Bundle extras = intent.getExtras();

    if (extras != null) {

// kill running alarm activity
        if (extras.containsKey("autoKill")) {

            Log.d("Ben", "AlarmReceiver killing running alarm NOW.");

            Intent bc = new Intent("PLAYER_STOP_SELF");
            LocalBroadcastManager.getInstance(context).sendBroadcast(bc);

            context.stopService(new Intent(context, StreamService.class));
            return;
        }

        label = extras.getString("label");
        id = extras.getInt("id");
    }

    Log.d("Ben", "AlarmReceiver ok!");


// CALC NEXT ALARM and start StreamingService...

    if (Build.VERSION.SDK_INT >= 26) {
        context.startForegroundService(new Intent(context, StreamService.class));
        context.startForegroundService(new Intent(context, CalcNextAlarmService.class));
        Log.d("Ben", "SDK >= 26 *** context.startForegroundServices");
    }
    else {
        context.startService(new Intent(context, StreamService.class));
        context.startService(new Intent(context, CalcNextAlarmService.class));
        Log.d("Ben", "SDK < 26 *** context.startServices");
    }
}

Сервис

@Override
public void onCreate() {


// initializing variables, shared preferences,... not shown

    Log.d("Ben", "StreamService calling PlayerActivity now...");

    startActivity(new Intent(this, PlayerActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));

// NOTI AND FOREGROUND!
    Notification noti = createForegroundNotification();
    startForeground(ntfctnId, noti);
// It doesn't even get to here before the delay...
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    Log.d("Ben", "StreamService onStartCommand");

Согласно Log.d:

07-14 14:30:01.335 D/Ben: Alarmreceiver HELLO
07-14 14:30:01.364 D/Ben: AlarmReceiver ok! (label: Alarm 1 - id: 10001)
07-14 14:30:01.372 D/Ben: SDK < 26 *** context.startServices
07-14 14:30:01.378 D/Ben: StreamService calling PlayerActivity now...
07-14 14:31:41.116 D/Ben: StreamService onStartCommand
07-14 14:31:41.224 D/Ben: StreamService wakeLock.isHeld()
    StreamService wifiLock.isHeld()
    *** onStartCommand ELSE ***
07-14 14:31:41.227 D/Ben: preparing player - start streaming in 2 seconds...
07-14 14:31:41.365 D/Ben: wakeLock.isHeld()
    wifiLock.isHeld()
07-14 14:31:41.366 D/Ben: PlayerActivity.onCreate()
07-14 14:31:43.229 D/Ben: Start Streaming now! (normal alarm)
07-14 14:31:43.241 D/Ben: buffering
07-14 14:31:43.242 D/Ben: buffering
07-14 14:31:44.345 D/Ben: ready

Будильник отлично работает в 95% случаев использования, но ИНОГДА эта дремота появляется и запускает будильник с опозданием на 1-15 минут - я отлаживаю это уже более 2 недель, переписал весь сервис и классы Receiver 2 раза и начинаю сходить с ума, помогите.

ИЗМЕНИТЬ

В итоге я использовал бодрствующий BroadcastReceiver и бодрствующий сервис (для всех API ‹ 26), который затем позаботится о соответствующем вызове других сервисов (то, что я делал в AlarmReceiver раньше, и все еще делаю для API >= 26)

Пока вроде работает нормально - только на одном из моих тестовых устройств с запущенным Lineage будильник иногда срабатывает поздно, на моем собственном телефоне для повседневного использования я тоже использую Lineage, но там все в порядке. Возможно, SGS 4 mini просто слишком стар (я не очень в это верю, но пока никто не жалуется, мне придется предположить, что он работает так, как ожидалось)

Спасибо за вашу помощь @Elletlar.


person Ben    schedule 14.07.2018    source источник
comment
Доза не помогает. Но эта реализация не будет работать и на устройствах с предварительной дозой, потому что startService может спать до вызова onStartCommand на этих устройствах. На устройствах до API 22 это обрабатывается путем получения статической частичной блокировки Wakelock в BroadcastReceiver и ее освобождения от службы. Для устройств API 22–25 это обрабатывается с помощью WakefulBroadcastReceiver. Если вы прочтете нижний раздел этого документа, в нем будут объяснены улучшения, которые необходимо внести для реализации версии до 26: Поддерживать устройство в активном состоянии   -  person Elletlar    schedule 14.07.2018
comment
Теперь для 26+ дремлющих устройств. Было бы хорошо, если бы ваша служба находилась в отдельном процессе. Это стандартная практика для приложений Google, поскольку она предотвращает загрузку ресурсов пользовательского интерфейса в память и раздувание процесса службы, но также приводит к тому, что Google пропускает серьезный дефект на некоторых устройствах, заключающийся в том, что службы переднего плана выполняются в основном процессе. можно дремать.   -  person Elletlar    schedule 14.07.2018
comment
Важными частями реализации 26+ являются: 1. Когда тревога отправлена, приложение также будет добавлено во временный белый список системы примерно на 10 секунд, чтобы позволить этому приложению получить дополнительные блокировки пробуждения для завершения своей работы. 2. Минимальный интервал между двумя сигналами тревоги по дозе обычно составляет ~9 минут. Обработка режима ожидания   -  person Elletlar    schedule 14.07.2018
comment
Это может быть полезно в отношении startForegroundService startForegroundService не вызывал startForeground, должен иметь канал уведомлений и ненулевой идентификатор.   -  person Elletlar    schedule 15.07.2018
comment
Спасибо за подробности. Я читал про отдельный процесс, но не знал, как это сделать, хотел указать его в манифесте, но полностью ли я свободен в выборе имени процесса? Не нашел полезного ответа через Google. Другое имя пакета? Могу ли я использовать mySeparateProcess в качестве имени процесса, и будет ли это так? --- Устройства Pre doze отлично работают для меня уже более 7 месяцев, я думаю, что оставляю их и меняю вещи только для Android 6+ --- хотел избежать бодрствования BR из-за устаревания, но попробую сейчас для СДК 22-25.   -  person Ben    schedule 15.07.2018
comment
Android 8+: уведомление переднего плана имеет правильный идентификатор и канал. Значит, все в порядке, как на Android 8+? (Задержка была замечена на устройстве Android 7, у меня нет настоящего устройства 8. Потому что я получаю пробуждения в onStartCommand, что должно быть легко выполнено в течение 10 секунд) -- Потребуются ли мне дальнейшие изменения на Android 8+?   -  person Ben    schedule 15.07.2018
comment
И еще один вопрос, касающийся WakefulBroadcastReceiver: могу ли я использовать свою службу переднего плана как есть, когда я звоню только другому (бодрствующему) широковещательному приемнику 22-25? Или мне лучше использовать IntentService и startWakfulService?   -  person Ben    schedule 15.07.2018
comment
Вы определенно можете назвать процесс как угодно, потому что я недавно унаследовал проект, используя имя процесса службы «что угодно», которое я быстро изменил, но стандартное имя по умолчанию android:process=:remote. Но имя процесса может быть видно пользователям, когда они заходят в настройки, поэтому, вероятно, лучше выбрать то, которое они могут понять. Я думаю, что проблемы с процессами заключаются в том, чтобы не создавать слишком много, потому что даже пустой процесс использует значительную часть квоты памяти приложения. Другое дело, что SharedPreferences становится сложным, потому что это небезопасно для разных процессов.   -  person Elletlar    schedule 15.07.2018
comment
Честно говоря, я действительно не уверен. Меня беспокоит то, что если вы просто вызовете startService на этих старых устройствах, вы столкнетесь с проблемами, для решения которых предназначен WakefulBroadcastReceiver. Но в то же время я не хочу призывать вас использовать устаревший компонент, если в этом нет необходимости. Существует также ContextCompat.startForegroundService, у которого не лучшая документация, но я подозреваю, что на старых устройствах он может просто вызвать startService.   -  person Elletlar    schedule 15.07.2018
comment
Еще одна вещь, которая меня беспокоит, дважды вызывая службу startForegroundService. Я бы не стал доверять фреймворку, чтобы справиться с этим. Я планирую свои будильники в основном сервисе, но в отдельном классе: например, «Планировщик».   -  person Elletlar    schedule 15.07.2018