Android WorkManager启动Worker两次
我有一组大任务要在后台执行:Android WorkManager启动Worker两次,android,kotlin,android-room,android-jetpack,android-workmanager,Android,Kotlin,Android Room,Android Jetpack,Android Workmanager,我有一组大任务要在后台执行: 存储数据 解析一堆文件并将它们存储在房间 出于这个原因,我创建了一个独特的工作者链,该链具有相同的标签 class GtfsStaticManager() { private val workerManager = WorkManager.getInstance() override fun load() { val constraints = Constraints.Builder().setRequiredNetworkType
房间
工作者链,该链具有相同的标签
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分钟。一段时间后,我注意到它再次排队,但第一个作业仍在运行,因此我有两个巨大的作业在后台运行,当然我的数据被复制了
我遵循了教程,我错过了什么吗
下面是我的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()
}
}
另外,我的依赖项是实现“android.arch.work:work runtime:1.0.0”
WorkManager中的工人类的执行限制为10分钟。
发件人:
系统指示应用程序出于某种原因停止工作。如果超过10分钟的执行期限,则可能发生这种情况。计划稍后重试该工作
在您的情况下,您没有处理工作的停止,但WorkManager将忽略任何结果,因为它将作业标记为“已取消”,并在可能的情况下再次执行
这可能导致您正在经历的双重执行
在不了解您想要实现的目标的情况下,很难提出替代方法。但是,一般来说,WorkManager适用于需要保证执行的可延迟任务
已在1.0版本后扩展,您可以在那里找到更多信息。您需要首先检查下载的文件是否存在于下载文件的路径上,然后将字节存储在循环内的SharedReferences中,这些字节以前从下载路径读取,一旦您的作业再次启动,然后首先检查下载的字节,下次从该偏移量开始
示例代码:
RandomAccessFile seeker = new RandomAccessFile(fname, "r");
seeker.seek(readOffset()); // move to the offset
seeker.readLine(); // and read the String
如果需要检查相同的数据库条目,则将行的状态标记为“成功”,以便下次跳过该行。谢谢,此限制对我来说是新的。因此,在我的例子中,要处理正确的取消
状态,我应该将while
循环更改为如下内容:while(line!=null | | | isStopped)
?我的目标很简单,在我下载了一个zip
文件后,我需要解压缩它并解析其中的csv
文件。在我的例子中,一个文件有400万行,并且将它们存储在文件室
需要一段时间。请记住,在这种情况下,WorkManager将忽略工作人员的返回值并重新安排它。这意味着您需要在离开工作人员之前跟踪处理数据的地点,或者在下次执行时,您可能会处理相同的数据两次,并被相同的10分钟限制所捕获。您能否建议我存储我的进度
值的最佳选项(静态变量、共享首选项等)?Android
world对我来说是新事物,所以我不确定如何做到最好。在这种情况下,共享Prefs似乎是一个不错的选择:但我不知道整个应用程序/用例,所以…阅读文档,检查此解决方案是否适用于您的特定问题。