Диспетчер периодической работы не показывает уведомление на пироге Android, когда не заряжается или выключен экран - PullRequest
0 голосов
/ 03 января 2019

У меня есть приложение, которое должно показывать уведомление каждые 2 часа и должно останавливаться, если пользователь уже действовал в отношении уведомления. Поскольку фоновые сервисы стали историей, я подумал об использовании WorkManager ("android.arch.work:work-runtime:1.0.0-beta01") для того же.

Моя проблема заключается в том, что, хотя менеджер работ успешно показывает уведомления при запуске приложения, но он не будет отображать уведомление последовательно в следующих случаях (я сократил временной интервал с 2 часов до 2 минут, чтобы проверить согласованность) :

  • когда приложение убивается из фона.
  • устройство выключено.
  • Состояние устройства в отключенном состоянии (т.е. не заряжается).

Под последовательностью я подразумеваю, что уведомления показываются хотя бы один раз за данный промежуток времени. в течение 2 минут частота уведомлений изменялась раз в 4 минуты, чтобы вообще не отображать никаких уведомлений. за 2 часа (время, которое я на самом деле хочу), это было 4 часа, и я не получил ни одного уведомления. Вот код, который я использую для вызова WorkManger:

    public class CurrentStreakActivity extends AppCompatActivity {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...

        setDailyNotifier();
        ...
    }

    private void setDailyNotifier() {
        Constraints.Builder constraintsBuilder = new Constraints.Builder();
        constraintsBuilder.setRequiresBatteryNotLow(false);
        constraintsBuilder.setRequiredNetworkType(NetworkType.NOT_REQUIRED);
        constraintsBuilder.setRequiresCharging(false);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            constraintsBuilder.setRequiresDeviceIdle(false);
        }

        Constraints constraints =constraintsBuilder.build();


        PeriodicWorkRequest.Builder builder = new PeriodicWorkRequest
                .Builder(PeriodicNotifyWorker.class, 2, TimeUnit.HOURS);

        builder.setConstraints(constraints);
        WorkRequest request = builder.build();
        WorkManager.getInstance().enqueue(request);

    }
    ....
}

Вот рабочий класс (я могу также опубликовать showNotif(..) и setNotificationChannel(...), если они могут быть ошибочными):

public class PeriodicNotifyWorker extends Worker {
    private static final String TAG = "PeriodicNotifyWorker";

    public PeriodicNotifyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
        Log.e(TAG, "PeriodicNotifyWorker: constructor called" );
    }

    @NonNull
    @Override
    public Result doWork() {
//        Log.e(TAG, "doWork: called" );

        SharedPreferences sp =
                getApplicationContext().getSharedPreferences(Statics.SP_FILENAME, Context.MODE_PRIVATE);
        String lastcheckin = sp.getString(Statics.LAST_CHECKIN_DATE_str, Statics.getToday());
//        Log.e(TAG, "doWork: checking shared preferences for last checkin:"+lastcheckin );

        if (Statics.compareDateStrings(lastcheckin, Statics.getToday()) == -1) {
            Log.e(TAG, "doWork: last checkin is smaller than today's date, so calling creating notification" );
            return createNotificationWithButtons(sp);
        }
        else {
            Log.e(TAG, "doWork: last checkin is bigger than today's date, so no need for notif" );
            return Result.success();
        }
    }


    private Result createNotificationWithButtons(SharedPreferences sp) {
        NotificationManager manager =
                (NotificationManager) getApplicationContext().getSystemService((NOTIFICATION_SERVICE));
        String channel_ID = "100DaysOfCode_ID";
        if (manager != null) {
            setNotificationChannel(manager,channel_ID);
            showNotif(manager, channel_ID, sp);
            return Result.success();
        }
        else {
            return Result.failure();
        }

Я использую устройство xiaomi miA2 androidOne с Android Pie (SDK 28). Меня беспокоит еще несколько вещей:

  • Что я могу сделать, чтобы узнать, работает ли мой WorkManager? Другие, которые просто ждут 2 часа и надеются на уведомление. Я на самом деле пробовал что-то подобное, держал телефон подключенным к компьютеру и время от времени проверял logcat от android studio. Он запускает все журналы, когда рабочий действительно вызывается, но я не думаю, что это правильный способ проверить это, или это так?
  • В приведенном выше коде setDailyNotifier() вызывается из onCreate() каждый раз, когда приложение открывается. Разве это не так? не должно быть какого-то уникального идентификатора для каждого WorkRequest и функции проверки, такой как WorkManger.isRequestRunning(request.getID), которая позволила бы нам проверить, выполняет ли работник уже заданное задание? Если это был случай AsyncTask, то мы будет беспорядок.

Я также проверил ответ @ commonsware здесь о wakelock, когда экран выключен, но я помню, что диспетчер работ использует диспетчер тревог внутри, когда он доступен. Так чего мне здесь не хватает?

Ответы [ 2 ]

0 голосов
/ 13 января 2019

На данный момент у меня установлено это приложение за последние 8 дней, и я могу подтвердить, что код правильный и приложение работает нормально.как говорит pfmaggi , минимальный интервал времени, в течение которого диспетчер работы может планировать работу, составляет 15 минут, поэтому вероятность того, что WorkManager сработает, как и ожидалось, в моих условиях тестирования (из 2 минут, меньше))Вот некоторые из моих других наблюдений:

  • Как я уже сказал в вопросе, я не смог получить уведомление в течение 4 часов, даже если я повторил интервал повторения как 2 часа.Это было из-за ,%20java.time.Duration,%20java.time.Duration)" rel="nofollow noreferrer"> Flex Time .Я прошел в гибкое время 15 минут, и теперь он показывает уведомления между правильным интервалом времени.поэтому я буду отмечать ответ Пфмаджи как правильный.
  • Проблема повторного запроса на работу может быть решена путем замены WorkManager.getInstance().enqueue(request) на WorkManager.getInstance().enqueueUniqueWork(request,..)

  • Я все еще не смогнайдите способ протестировать менеджера по работе описанным мною способом.

0 голосов
/ 05 января 2019

Несколько комментариев:
WorkManager имеет минимальный периодический интервал 15 минут и не гарантирует выполнение вашей задачи в точное время.Вы можете прочитать больше об этом в этом блоге .

Все обычные ограничения фона, которые есть у вас в новых выпусках Android, по-прежнему актуальны, когда вы используете WorkManager для планирования своих задач.WorkManager гарантирует, что задача будет выполнена, даже если приложение будет удалено или устройство будет перезагружено, но не может гарантировать точное выполнение.

Существует одно примечание о переназначении задач, когда ваше приложение будет убито.Некоторые OEM-изготовители внесли изменения в ОС и приложение Launcher, которые не позволяют WorkManager выполнить эти функции.

Вот обсуждение Issetracker :

ДаЭто правда, даже когда телефон является китайским телефоном.
Единственная проблема, с которой мы столкнулись, - это случай, когда некоторые китайские OEM-производители рассматривают смахивание, чтобы уволить его из Recents, как принудительную остановку.Когда это произойдет, WorkManager перепланирует все ожидающие задания при следующем запуске приложения.Учитывая, что это нарушение CDD, WorkManager может сделать немного больше, учитывая свою клиентскую библиотеку.

Чтобы добавить к этому, если производитель устройства решил изменить стандартный Android, чтобы принудительно остановить приложение, WorkManager перестанет работать (как и JobScheduler, аварийные сигналы, широковещательные приемники и т. Д.).Нет способа обойти это.К сожалению, некоторые производители устройств делают это, поэтому в этих случаях WorkManager перестанет работать до следующего запуска приложения.

...