ОАО «Российская Авиакомпания ЭРЛЕН»

Russian Airlines Company "Airlen"

Ваш внешний IP: 3.239.76.25

Запуск фоновых задач в Android с помощью WorkManager: часть 4

Предыдущая статья из этой серии: Запуск фоновых задач в Android с помощью WorkManager: часть 3

Отправка и получение данных

В этой статье мы рассмотрим, как передать данные в задачу и как получить результат.

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

Входные данные

Во-первых, давайте посмотрим, как передать входные данные в задачу:

val myData: Data = Data.Builder()  
    .putString("keyA", "value1")  
    .putInt("keyB", 1)  
    .build()

val myWorkRequest: OneTimeWorkRequest = OneTimeWorkRequestBuilder<MyFirstWorker>()  
    .setInputData(myData)  
    .build()

  
WorkManager  
    .getInstance(this)  
    .enqueue(myWorkRequest)

Данные помещаются в Dataобъект с помощью его построителя. Далее мы передаем этот объект в setInputDataметод построителя WorkRequest.

Когда задача запущена, то внутри нее (в MyFirstWorker) мы можем получить ввод вот так:

class MyFirstWorker(context: Context, parameters: WorkerParameters): Worker(context, parameters) {  

    private val TAG = this.javaClass.simpleName  

    override fun doWork(): Result {  

        val valueA = inputData.getString("keyA")  
        val valueB = inputData.getInt("keyB", 0)  
        Log.d(TAG, "doWork:valueA $valueA")  
        Log.d(TAG, "doWork:valueB $valueB")  

        return Result.success()  

    }  

}

Журналы:

2023-04-20 12:44:00 29725-29754 MyFirstWorker D  doWork:valueA value1
2023-04-20 12:44:00 29725-29754 MyFirstWorker D  doWork:valueB 1

Выходные данные

Чтобы задача вернула данные, вы должны передать их методу setOutputData. Код MyFirstWorkerбудет таким:

    override fun doWork(): Result {   

        val output = Data.Builder()  
            .putString("keyC", "value11")  
            .putInt("keyD", 11)  
            .build()  

        return Result.success(output)  

    }

Мы можем получить этот вывод из WorkInfo:

WorkManager  
    .getInstance(this)  
    .getWorkInfoByIdLiveData(myWorkRequest.id)  
    .observe(this) { info ->  
        when (info?.state) {  
            WorkInfo.State.FAILED -> {  

            }  

            WorkInfo.State.SUCCEEDED -> {  

                val valueC = info.outputData.getString("keyC")  
                val valueD = info.outputData.getInt("keyD", 0)  
                Log.e(TAG, "value: $valueC" )  
                Log.e(TAG, "value: $valueD" )  

            }  

            else -> {  

            }  

        }  

    }

Результат:

2023-04-21 08:33:20 32749-32749 WorkManagerActivity E  value: value11
2023-04-21 08:33:20 32749-32749 WorkManagerActivity E  value: 11

Объект Data, в котором хранятся данные, имеет getKeyValueMapметод, который возвращает вам Mapвсю информацию об этом файле Data.

И Data.Builderимеет putAll(Map<String, Object> values)метод, в который можно передать Mapвсю информацию, которая будет помещена в Data.

Данные между задачами

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

Например, запускаем последовательность из первой и второй задач:

WorkManager  
    .getInstance(this)  
    .beginWith(myWorkRequest1)  
    .then(myWorkRequest2)  
    .enqueue()

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

    override fun doWork(): Result {    

        val output = Data.Builder()  
            .putString("keyA", "value1")  
            .putInt("keyB", 1)  
            .build()  

        return Result.success(output)  

    }

Тогда во втором они придут на вход и мы сможем их получить обычным способом:

override fun doWork(): Result {  

    val valueA = inputData.getString("keyA")  
    val valueB = inputData.getInt("keyB", 0)  
    Log.d(TAG, "doWork:valueA $valueA")  
    Log.d(TAG, "doWork:valueB $valueB")  

    return Result.success()  

}

Журналы:

2023-04-21 08:53:24 628-661 MySecondWorker D  doWork:valueA value1
2023-04-21 08:53:24 628-661 MySecondWorker D  doWork:valueB 1

Немного усложним пример:

WorkManager  
    .getInstance(this)  
    .beginWith(listOf(myWorkRequest1, myWorkRequest2))  
    .then(myWorkRequest3)  
    .enqueue()

Параллельно выполняются первая и вторая задачи, затем выполняется третья. В результате выход из первой и второй задачи попадет в третью. Посмотрим, как получится.

Пусть первая задача возвращает следующие данные:

    override fun doWork(): Result {  

        val output = Data.Builder()  
            .putString("keyA", "value1")  
            .putInt("keyB", 1)  
            .putString("keyC", "valueC")  
            .build()  

        return Result.success(output)  

    }

И второй такой:

    override fun doWork(): Result {  

        val output = Data.Builder()  
            .putString("keyA", "value2")  
            .putInt("keyB", 2)  
            .putString("keyD", "valueD")  
            .build()  

        return Result.success(output)  

    }

Обратите внимание, я специально сделал одинаковые ключи: keyAи keyBдля того, чтобы проверить, какие значения этих ключей придут в третью задачу — из первой задачи или из второй.

Вывожу в лог входные данные третьей задачи:

    override fun doWork(): Result {  

        Log.d(TAG, "data " + inputData.keyValueMap)  
        
        return Result.success()  

    }

Результат:

2023-04-21 09:04:02 783-838 MyThirdWorker D data {keyA=value2, keyB=2, keyC=valueC, keyD=valueD}

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

2023-04-21 09:05:47 963-995 MyThirdWorker D data {keyA=value1, keyB=1, keyC=valueC, keyD=valueD}

Теперь мы видим значения первой задачи в ключах keyAи keyB.

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

ВводСлияние

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

Рассмотрим еще один InputMerger — ArrayCreatingInputMerger. Если ключи совпадают, он создаст массив, в который поместит все значения этого ключа.

Укажем его для третьей задачи с помощью метода setInputMerger:

val myWorkRequest3: OneTimeWorkRequest = OneTimeWorkRequestBuilder<MyThirdWorker>()  
    .setInputMerger(ArrayCreatingInputMerger::class.java)  
    .build()

Теперь будет ArrayCreatingInputMergerиспользоваться при объединении выходных данных предыдущих задач с входными данными третьей задачи.

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

    override fun doWork(): Result {  

        val valueA = inputData.getStringArray("keyA")  
        val valueB = inputData.getIntArray("keyB")  
        val valueC = inputData.getStringArray("keyC")  
        val valueD = inputData.getStringArray("keyD")  

        Log.d(TAG, "valueA ${valueA?.toList()}")  
        Log.d(TAG, "valueB ${valueB?.toList()}")  
        Log.d(TAG, "valueC ${valueC?.toList()}")  
        Log.d(TAG, "valueD ${valueD?.toList()}")  

        return Result.success()  

    }

Давайте используем тот же пример, чтобы проверить это:

WorkManager  
    .getInstance(this)  
    .beginWith(listOf(myWorkRequest1, myWorkRequest2))  
    .then(myWorkRequest3)  
    .enqueue()

Первая задача вернет следующие данные:

val output = Data.Builder()  
    .putString("keyA", "value1")  
    .putInt("keyB", 1)  
    .putString("keyC", "valueC")  
    .build()

а второй такой:

val output = Data.Builder()  
    .putString("keyA", "value2")  
    .putInt("keyB", 2)  
    .putString("keyD", "valueD")  
    .build()

В третьем мы получим следующие входные данные:

2023-04-21 10:22:55  2307-2340  MyThirdWorker D valueA [value2, value1]
2023-04-21 10:22:55  2307-2340  MyThirdWorker D valueB [2, 1]
2023-04-21 10:22:55  2307-2340  MyThirdWorker D valueC [valueC]
2023-04-21 10:22:55  2307-2340  MyThirdWorker D valueD [valueD]

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


Также опубликовано здесь .

Запуск фоновых задач в Android с помощью WorkManager: часть 4
Запуск фоновых задач в Android с помощью WorkManager: часть 4
Февраль 2024
Пн Вт Ср Чт Пт Сб Вс
 1234
567891011
12131415161718
19202122232425
26272829  

Сервер: 29.02.2024 07:02