android - WorkManager两次启动Worker

标签 android kotlin android-room android-jetpack android-workmanager

我有一组大型任务要在后台执行:

  • 住宿数据
  • 解析一堆文件并将其存储在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()
        }
    }
    

    除一件事情外,其他所有东西都工作正常:其中一个文件具有400万条记录,大约需要10-15分钟才能完成。一段时间后,我注意到它又重新加入了队列,但第一个作业仍在运行,因此结果是我有2个巨大的作业在后台运行,当然我的数据已被复制。

    我遵循了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()
        }
    }
    

    附言我的依赖是implementation "android.arch.work:work-runtime:1.0.0"

    最佳答案

    在WorkManager中,工作程序类的执行限制为10分钟。
    WorkManager guide on how to handle cancellation:

    The system instructed your app to stop your work for some reason. This can happen if you exceed the execution deadline of 10 minutes. The work is scheduled for retry at a later time.



    在您的情况下,您没有处理工作的停止,但是WorkManager将忽略任何结果,因为它将作业标记为“已取消”,并在可能的情况下再次执行。

    这可能会导致您遇到双重执行。

    在不进一步了解您要实现的目标的情况下,很难提出另一种方法,但是,作为一般规则,WorkManager适用于需要保证执行的可延期任务。

    WorkManager documentation在1.0版本之后进行了扩展,您可以在此处找到更多信息。

    关于android - WorkManager两次启动Worker,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55383105/

    相关文章:

    java - 抽屉导航 Activity 从外部按钮更改 fragment

    jackson - 如何在 Kotlin 中使用 Jackson JsonSubTypes 注解

    kotlin - 了解 Kotlin 的必要性

    android - 带有字符串的枚举或密封类

    android - Room LiveData vs AsyncTask 用于不需要更新的单个查询

    java - 从在后台线程上执行的方法获取 int 值

    android - Android 智能手机上的固定宽度 html 布局

    android - 在 ImageView 中加载重位图的最佳方法是什么?

    android 中带有 HttpsURLConnection 的 java.net.protocolException

    android - 房间错误 : no viable alternative at input?