WorkManager дважды запустить Worker - PullRequest
0 голосов
/ 27 марта 2019

У меня есть набор больших задач, которые я хочу выполнить в фоновом режиме:

  1. Loding data
  2. Анализ группы файлов и сохранение их в Room

По этой причине я создал уникальную цепочку Worker с теми же tag.

class GtfsStaticManager() {
    private val workerManager = WorkManager.getInstance()

    override fun load() {
        val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()

        val inputData = GtfsStaticLoadDataWorker.inputData(staticUrl, cacheDir)
        // 1. Loading data
        val downloadWorkRequest = OneTimeWorkRequest.Builder(GtfsStaticLoadDataWorker::class.java)
            .addTag("GTFS")
            .setConstraints(constraints)
            .setInputData(inputData)
            .build()

        // 2. List of Workers to parse and store data to the Room
        val parseWorkers = GtfsFile.values().map {
            OneTimeWorkRequest.Builder(GtfsStaticParseFileWorker::class.java)
                .setInputData(GtfsStaticParseFileWorker.inputData(it.file, cacheDir + File.separator + "feed"))
                .addTag("GTFS")
                .build()
        }

        workerManager
            .beginUniqueWork("GTFS", ExistingWorkPolicy.KEEP, downloadWorkRequest)
            .then(parseWorkers)
            .enqueue()
    }
}

Все отлично работает, кроме одного: один из файлов имеет 4 миллиона записей иэто займет около 10-15 минут, чтобы закончить его.Через некоторое время я заметил, что он снова был поставлен в очередь НО , первое задание все еще выполнялось, в результате у меня есть 2 огромных задания, работающих в фоновом режиме, и, конечно, мои данные были продублированы.

Iследовал учебнику codelabs , я что-то пропустил?

Ниже мой Worker с логикой синтаксического анализа:

class GtfsStaticParseFileWorker(
    context: Context,
    workerParameters: WorkerParameters
) : Worker(context, workerParameters) {
    private val fileName: String get() = inputData.getString(FILE_NAME) ?: ""
    private val cacheDir: String get() = inputData.getString(UNZIP_FOLDER) ?: ""

    companion object {
        private const val FILE_NAME = "FILE_NAME"
        private const val UNZIP_FOLDER = "UNZIP_FOLDER"
        fun inputData(fileName: String, cacheDir: String) = Data
            .Builder()
            .putString(FILE_NAME, fileName)
            .putString(UNZIP_FOLDER, cacheDir)
            .build()
    }

    override fun doWork(): Result {
        val db = LvivTransportTrackerDataBase.getUpdateInstance(applicationContext)
        val agencyRepository = AgencyRepository(db.agencyDao())
        val calendarRepository = CalendarRepository(db.calendarDao())
        val calendarDateRepository = CalendarDateRepository(db.calendarDateDao())
        val routeRepository = RouteRepository(db.routeDao())
        val stopTimeRepository = StopTimeRepository(db.stopTimeDao())
        val stopRepository = StopRepository(db.stopDao())
        val tripRepository = TripRepository(db.tripDao())

        val file = File(cacheDir + File.separator + fileName)
        val fileType = GtfsFile.from(fileName) ?: return Result.failure()

        when (fileType) {
            GtfsFile.Agency -> agencyRepository.deleteAll()
            GtfsFile.CalendarDates -> calendarDateRepository.deleteAll()
            GtfsFile.Calendar -> calendarRepository.deleteAll()
            GtfsFile.Routes -> routeRepository.deleteAll()
            GtfsFile.StopTimes -> stopTimeRepository.deleteAll()
            GtfsFile.Stops -> stopRepository.deleteAll()
            GtfsFile.Trips -> tripRepository.deleteAll()
        }

        FileInputStream(file).use { fileInputStream ->
            InputStreamReader(fileInputStream).use inputStreamReader@{ inputStreamReader ->
                val bufferedReader = BufferedReader(inputStreamReader)
                val headers = bufferedReader.readLine()?.split(',') ?: return@inputStreamReader
                var line: String? = bufferedReader.readLine()

                while (line != null) {
                    val mapLine = headers.zip(line.split(',')).toMap()

                    Log.d("GtfsStaticParse", "$fileType: $line")
                    when (fileType) {
                        GtfsFile.Agency -> agencyRepository.create(AgencyEntity(mapLine))
                        GtfsFile.CalendarDates -> calendarDateRepository.create(CalendarDateEntity(mapLine))
                        GtfsFile.Calendar -> calendarRepository.create(CalendarEntity(mapLine))
                        GtfsFile.Routes -> routeRepository.create(RouteEntity(mapLine))
                        GtfsFile.StopTimes -> stopTimeRepository.create(StopTimeEntity(mapLine))
                        GtfsFile.Stops -> stopRepository.create(StopEntity(mapLine))
                        GtfsFile.Trips -> tripRepository.create(TripEntity(mapLine))
                    }

                    line = bufferedReader.readLine()
                }
            }
        }

        return Result.success()
    }
}

PS моя зависимость implementation "android.arch.work:work-runtime:1.0.0"

1 Ответ

0 голосов
/ 28 марта 2019

Рабочие классы в WorkManager имеют ограничение на выполнение в 10 минут.
Из Руководства WorkManager по обработке отмены :

Система приказала вашему приложению по какой-то причине прекратить работу. Это может произойти, если вы превысите срок исполнения 10 минут. Работы планируется повторить позже.

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

Это может привести к двойному выполнению, которое вы испытываете.

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

Документация WorkManager была расширена после выпуска 1.0, и вы можете найти больше информации там.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...