BroadcastReceiver запускает активность со случайной задержкой - PullRequest
0 голосов
/ 24 июня 2018

Я работаю над будильником, и у меня есть серьезная проблема, BroadCastReceiver всегда вызывается точно в срок , я выполняю какую-то работу, например, собираю преднамеренные дополнения, ничего тяжелого или долго, а затем я вызываю тревожную активность.

Там есть очень странное поведение, много раз он просто отлично работает, но иногда вызов активности задерживается , и я говорю о 1-13 минут в моих тестах до сих пор, что совершенно неприемлемо для приложения тревоги. Это происходит, когда устройство выходит из режима ожидания.

Я использую setExactAndAllowWhileIdle(), который действительно работает как талисман при вызове получателя, но не запускается активность с получателя.

Вот часть кода получателя:

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

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

[...]

Log.d("Ben", "Alarmreceiver CALLING WAKE SCREEN NOW");

        if (wait) {
            new Thread(new Runnable() {
                @Override
                public void run() {

                    Log.d("Ben", "AlarmReceiver: Alarm still running, wait for finsihing...");

                    try {
                        Thread.sleep(3_000);
                    } catch (Exception e) {
                        context.startActivity(new Intent("package.action.alarm").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
                    }
                    context.startActivity(new Intent("package.action.alarm").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
                }
            }).start();
        }

        else
            context.startActivity(new Intent("package.action.alarm").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));

        Log.d("Ben", "Call done.");
    }
//end of receiver

Вот что я получаю от LogCat:

06-24 20:50:02.623 6527-6527/package D/Ben: Alarmreceiver HELLO
06-24 20:50:02.753 6527-6527/package D/Ben: Alarmreceiver CALLING WAKE SCREEN NOW
06-24 20:50:02.794 6527-6527/package D/Ben: Call done.
06-24 20:55:09.129 6527-6527/package D/Ben: AlarmActivity.onCreate()

Как вы видите, между командой и фактическим началом действия есть задержка в 5 минут!

Видно, что Log.d "вызов завершен" достигается менее чем через 200 мс. Запуск не должен быть проблемой, так как он даже не был запущен в этом случае. (Он ожидает завершения ранее запущенного сигнала тревоги, если он был запущен)

Log.d из AlarmActivity.onCreate() - самое первое утверждение в AlarmActivity, сразу после этого я получаю wakelocks.

Я пытался: intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);, так как я нашел это здесь в другом посте, но никаких изменений в поведении вообще.

Это действительно расстраивает - кто-нибудь знает, почему это происходит или как я могу это исправить?

EDIT

Теперь, когда я обменял новую тему на следующий код:

final PendingResult result = goAsync();

    Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            context.startActivity(new Intent("package.action.alarm").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));

            Log.d("Ben", "Runnable done.");
            result.finish();
        }
    }, 2_000);

все кажется работает нормально. Сегодня я провел 5 долгосрочных тестов, где я установил будильник на +50 или 60 минут каждый, чтобы убедиться, что система обязательно находится в режиме ожидания (я не доверяю режиму adb force doze):

Первые 3 пробега с goAsync пробежали идеально вовремя.

Четвертый прогон, в котором я изменил код обратно на поток без явного перехода в асинхронное состояние, снова опоздал более чем на 4 минуты.

Пятый тест с postDelayed и goAsync снова прошел идеально.

Я считаю, что сейчас это работает надежно, пока оно не зазвонит слишком поздно. Огромное спасибо Джонасу !!! Я боролся с этой проблемой в течение МЕСЯЦЕВ, думая, что новый поток будет достаточно асинхронным;)

РЕДАКТИРОВАТЬ 2:

Я проверил все это еще 1 неделю, и он все еще не работает. После того, как я изменил свою работоспособность на:

Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                context.startActivity(new Intent("package.action.alarm").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
                Log.d("Ben", "Activity has been called.");

// give an extra 4.5 sec window to start activity and alarm stream...
                Handler h = new Handler();
                h.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        result.finish();
                        Log.d("Ben", "Allowing Rec. finish now...");
                    }
                }, 4_500);
            }
        }, 2_000);

работает нормально, но не на 100%. (2 секунды - чтобы закончить уже запущенный сигнал тревоги, и с 4,5 секундами я надеюсь дать активности и обслуживанию достаточно времени для запуска потока, тогда он будет работать нормально)

Дополнительная информация:

Приемник запускает Активность, и первым действием там является приобретение Wakelocks (Wi-Fi и питание) и включение экрана. После этого я выполняю обработку телефонных звонков, а после этого запускаю службу переднего плана, которая будет транслировать музыку.

У меня есть Log.d повсюду, и я вижу, что иногда, когда поток буферизует слишком долго - так, что прошло 4,5 секунды в BR, устройство засыпает и не начинает потоковую передачу музыки до случайного время прошло снова (окно технического обслуживания, я думаю), ДАЖЕ ЕСЛИ БУДЕТЕ УЖЕ БЫЛО, УЖЕ ПРИОБРЕТЕНО.

Это не имеет никакого отношения к Runnable, я теперь выяснил. Я удалил его и вызвал Activity прямо в конце BR, что привело к почти определенной задержке в несколько минут в процедуре запуска активности. Без асинхронности - еще быстрее засыпает ...

Как мне начинать действие с приемника вещания, который не засыпает / не дремлет, когда БР закончен?

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

То же самое происходит, когда я запускаю службу переднего плана из BR.Служба переднего плана иногда останавливается в середине onCreate, потому что BR заканчивается, и устройство, кажется, спит (задремал) ...

Я действительно в отчаянии.

Когда я дал 7,5 вместо 4,5 секунд второму работоспособному в BR, я мог заметить ANR в консоли Google.(Хотя я считаю, что сигнализация работала нормально).

Как правильно решить эту проблему?Запуск asyncTask?

РЕДАКТИРОВАТЬ 3:

Джонас, спасибо за ваш ответ еще раз - я целую неделю пробовал много разных подходов, и на моих устройствах все выглядит нормально,но пользователи сообщают о задержках до 13 минут…

2 вещи, которые я пробовал:

  • запуск ForegroundService с уведомлением и wakelocks как единственное действие в AlarmReceiverи выполняя всю работу внутри службы

  • , удаляя приемник и запуская AlarmActivity напрямую, чтобы выполнить все как можно быстрее - захватить пробуждения и включить экран в качестве первого шага в упражнении,после этого получаю IntentExtras и запускаю музыку StreamService в качестве третьей вещи (все это в течение 1-2 секунд)

этот второй подход - мое текущее состояние, и я думал, что он работает хорошо, пока кто-тоснова сообщил о 13-минутной задержке.

ForegroundService вообще не работал - он часто засыпал передКогда играла музыка ... Я позволил завершить эту службу только тогда, когда музыка уже начала играть, но иногда это происходило после задержки - я понятия не имею, как?Это не может быть правильным, служба переднего плана с удерживаемыми wakelocks ДОЛЖНА держать устройство в активном состоянии!?!?

(я бы опубликовал Activity, но он состоит из 750 строк, так что ... нет.)

В любом случае: что еще я могу сделать, чтобы ДЕЙСТВИТЕЛЬНО удерживать / выводить устройство из режима ожидания?

  1. setExactAndAllowWhileIdle РАБОТАЕТ ОТЛИЧНО

  2. получение wakelocks работает отлично

  3. получение IntentExtras кажется, работает хорошо

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

музыкальный сервис запускается, но не завершает буферизацию из-за (я полагаю) режима ожидания снова

воспроизведение музыки начинается через x минут

это то, что я видел в журналах, теперь он работает нормально в 99% случаев, но все еще редко.Что мне не хватает?Есть ли магическая функция, которая не дает дремать в течение x минут?

1 Ответ

0 голосов
/ 12 июля 2018

Теперь я думаю, что это исправлено, переписав процедуру запуска и перейдя непосредственно к службе foregroundService.

Что касается задержки: я недавно изменил setExactAndAllowWhileIdle на setAlarmClock итеперь я на 100% уверен, что последний опаздывает в режиме ожидания (часто) - хорошая работа для видимой пользователем функции тревоги, у которой нет другого варианта использования.

Это было даже поздно, когда яsetExactAndAllowWhileIdle 10 секунд до времени будильника и setAlarmClock до «сейчас + 10 секунд».(С опозданием на 1:55 ...)

Итак, я вернулся к setExactAndAllowWhileIdle , который всегда вовремя вызывает BroadcastReceiver - всегда!

Iпереписал всю процедуру запуска еще раз (менял ее очень часто, поскольку сбой очень случайно и редко появлялся на моих тестовых устройствах)

Первый (старый) подход, который долго работалвремя:

setExactAndAllowWhileIdle -> BroadcastReceiver -> AlarmActivity -> StreamingService (Foreground).

Это работало хорошо в течение нескольких месяцев, но внезапно у меня были задержки 1-15 минут (окно обслуживания, я думаю), и журналы сообщали мне, что иногда даже служба переднего плана запускалась, музыка (ExoPlayer) начала буферизоваться, но была прервана (думаю, доза) и продолжала буферизацию и воспроизведение после случайной задержки.

Достаточно странно внутри ForegroundService, не так ли?

Мой новый подход:

setExactAndAllowWhileIdle -> BroadcastReceiver -> StreamService -> startActivity (подмышечныйmActivity) -> (startForeground (StreamService)) -> начать потоковую передачу музыки

Это отлично работало на 3 разных устройствах во всех моих тестах в течение двух дней, а также по утрам после длительного периода бездействия.

BroadcastReceiver (здесь удалено все асинхронное)

public class AlarmReceiver extends BroadcastReceiver {

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

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

    Bundle b = intent.getExtras();
    int intentId = 1909;

    Intent alarmIntent = new Intent(context, StreamService.class);
    if (b != null) {
        alarmIntent.putExtras(b);
        intentId = b.getInt("id");
        Log.d("Ben", "AlarmReceiver found ID: " + intentId);
    }

// CALC NEXT ALARM and start StreamingService...

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

Дополнительная информация:

В сервисе я запускаю активность экрана тревоги в onCreate(), а затеммузыкальный поток внутри onStartCommand() после startForeground().

Сейчас я рассматриваю это как свое рабочее решение, пока не заметил иное.Спасибо за вашу помощь и предложения, Джонас Лохманн!

РЕДАКТИРОВАТЬ: сигнал тревоги снова опоздал ... Я начну новый чистый пост о переднем плане службы, пострадавших от дозы ...

...