Как создать задание с помощью WorkManager, когда устройство подключено?

Я хочу создать задание, которое будет запускаться при подключении устройства, как широковещательный приемник для ACTION_POWER_CONNECTED.

Вот рабочий класс:

public class ChargerWorker extends Worker {

/* Constants */
    private static final String TAG = "ChargerWorker";
    private static final long TRIGGER_AGE = TimeUnit.MINUTES.toMillis(30);       // At least 30 min old.

    @NonNull
    @Override
    public Result doWork() {
        Log.e(TAG, "Power connection worker of Indoor/Outdoor lib.");
        IndoorOutdoorLogger.v(TAG, "Power connection worker of Indoor/Outdoor lib.");
        Context context = getApplicationContext();

        if (Conditions.isBatteryChargingOnAC(context)) {
            IndoorOutdoorLogger.d(context, TAG, "Power plugged and connected to AC.");
            Log.e(TAG, "Power plugged and connected to AC.");

            if (WiFiConnection.isWifiConnected(context) && WiFiConnection.isCurrentNetworkIndoorRecognized(context)) {
                // In this case an "upgrade" to the confidence level is possible.
                // Only run when the last known detection is old enough.
                DetectionResult latestResult = DetectionResult.loadFromCache(context);
                if (!latestResult.isTimestampValid(TRIGGER_AGE)) {
                    IndoorOutdoorLogger.d(context, TAG, "AC power while connected to a recognized WiFi network, and last detection is old enough, starting detection.");
                    IndoorOutdoorClient client = new IndoorOutdoorClient(context, null);
                    client.startShortDetection(Trigger.POWER);
                }
            }
        }
        return Result.SUCCESS;
    } }

Вот как я инициализирую работу в моем методе onCreate():

Constraints constraints = new Constraints.Builder().setRequiresCharging(true).build();
        OneTimeWorkRequest simpleReuquest = new OneTimeWorkRequest.Builder(ChargerWorker.class)
                .setConstraints(constraints)
                .build();
        WorkManager.getInstance().enqueue(simpleReuquest);

При первом подключении устройства к адаптеру все работает как надо. Однако, когда я отсоединяю устройство и пытаюсь снова, я больше никогда не получаю доступ к функции doWork. Вместо этого я вижу следующее сообщение в logcat:

E/WorkerWrapper: Status for 031e39f1-bc10-4a35-9341-11453fc0ca21 is SUCCEEDED; not doing any work.

Это потому, что я использую OneTimeWorkRequest? Если да, то как я могу запланировать его запуск каждый раз, когда устройство подключено к источнику питания?


person Keselme    schedule 25.03.2019    source источник


Ответы (2)


Это в, так как вы используете OnTimeWorkRequest, из его имени вы можете сделать вывод, что запрос действителен только один раз. После срабатывания он больше не будет вызываться, пока вы снова не поставите его в очередь.
Проблема в том, что WorkManager не поддерживает другие запросы или ограничения, соответствующие вашим потребностям. Взгляните на этот вопрос.

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

Вы можете использовать 2 типа WorkRequests вместе:

  • OneTimeWorkRequest это фактическая логика вашего алгоритма. Установите ограничения только при зарядке.
    После запуска этот рабочий процесс ставит в очередь PeriodicWorkRequest без каких-либо ограничений и Минимальный интервал повторения, который можно задать, составляет 15 минут

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

Таким образом, вы не обнаружите быстрых изменений состояния питания устройства, но это лучший вариант для Android Oreo (и выше), поскольку приложения, предназначенные для API уровня 26 или выше, больше не могут регистрировать приемники широковещательных сообщений для неявных широковещательных сообщений в своем манифесте

Чтобы проверить, подключено ли ваше устройство к сети:

Вы даже можете определить, что это за зарядка, используйте этот код:

IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, ifilter);

// Are we charging / charged?
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                 status == BatteryManager.BATTERY_STATUS_FULL;

// How are we charging?
int chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC;

взято прямо из руководства для разработчиков Android

Чтобы отменить WorkRequest:

Во-первых, создайте его с помощью tag:

OneTimeWorkRequest.Builder(MyWorker.class)
            .setConstraints(myConstraints)
            .addTag(tag)
            .build();

а затем сделать WorkManager.getInstance().cancelAllWorkByTag(tag)

Другой вариант — поставить в очередь уникальную работу:

WorkManager.getInstance().enqueueUniquePeriodicWork(
            uniqueWorkName, ExistingPeriodicWorkPolicy.REPLACE, periodicWork);

а затем отменить его с помощью WorkManager.getInstance().cancelUniqueWork(workName)

person ronginat    schedule 25.03.2019
comment
Спасибо, я просмотрел указанный ответ, однако они предлагают использовать BatteryManager и приемник ACTION_POWER_CONNECTED, поскольку я нацелен на Android 8 и выше, я не могу использовать неявные трансляции в манифесте. Вот почему я хотел использовать WorkManager. Я попробую ваш другой подход с PeriodicWorkRequest. Не могли бы вы объяснить эту часть: .. каждый этот период времени, даже после первого срабатывания, поэтому, если вы заряжаете свое устройство вдвое больше, работник будет вызываться дважды...? - person Keselme; 25.03.2019
comment
Конечно, допустим, вы создали PeriodicWorkRequest с интервалом в 15 минут. Теперь, когда вы заряжаете свое устройство в течение 30 минут, ваш воркер сработает дважды. PeriodicWorkRequest по-прежнему будет срабатывать, когда все его ограничения верны и каждые 15 минут. Вы не упомянули, нужно ли вам, чтобы ваш рабочий работал только один раз при каждой зарядке или нет, поэтому я добавил этот подход. - person ronginat; 25.03.2019
comment
Я думаю, что первый подход лучше и не так сложен в реализации. - person ronginat; 25.03.2019
comment
Я хочу, чтобы он запускался только один раз, когда он был подключен, я думаю, я могу справиться со случаем, когда он заряжается более 15 минут и срабатывает. - person Keselme; 25.03.2019
comment
рад, что смог помочь! - person ronginat; 25.03.2019
comment
Еще один момент, который я заметил в этом комментарии: я думаю, что первый подход лучше и не так сложен в реализации. Вы имеете в виду подход с двумя OneTimeWorkRequests? - person Keselme; 25.03.2019
comment
Да. Видите ли, с PeriodicWorkRequest вам все равно понадобится некоторая информация о том, был ли ваш воркер активирован ранее для текущей зарядки. Таким образом, может быть проще использовать 2 OneTimeWorkerRequests - person ronginat; 25.03.2019
comment
Я не думаю, что этот подход работает, я попробовал его, и когда я подключаю устройство, он запускает рабочий процесс onCharge, когда я его отключаю, он не запускает другого рабочего. Поэтому, когда я попытался подключить его снова, я получил сообщение: Состояние для bda5ca96-2a5d-42ad-9aee-bdaa23ed3176 УСПЕШНО; не делая никакой работы. - person Keselme; 25.03.2019

Вы должны использовать PeriodicWorkRequest, который позволит вашему менеджеру работ работать много раз в то время, когда вы выбираете Fays Minutes Hours, как хотите.

person Basel Beso    schedule 29.08.2019