工作管理器android:将文件写入本地存储时UI阻塞

问题描述 投票:2回答:2

这是我的工人班:

 class CoroutineDownloadJSONWorker(val context: Context, params: WorkerParameters) :
        CoroutineWorker(context, params) {
        private var notificationManager: NotificationManager? = null

        companion object {
            private const val WORK_NAME = "CoroutineDownloadJSONWorker"
            const val PARAM_PROGRESS = "Progress"

            fun run(context: Context): LiveData<WorkInfo> {
                val work = OneTimeWorkRequestBuilder<CoroutineDownloadJSONWorker>()
                    .build()

                val manager = WorkManager.getInstance(context)
                manager.enqueueUniqueWork(WORK_NAME, ExistingWorkPolicy.REPLACE, work)
                return manager.getWorkInfoByIdLiveData(work.id)
            }

            fun stop(context: Context) {
                //  Timber.d("stop")
                val manager = WorkManager.getInstance(context)
                manager.cancelUniqueWork(WORK_NAME)
            }
        }

        override suspend fun doWork(): Result {
            notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            val progress = "Starting Download"
            setForegroundAsync(createForegroundInfo(progress))
            val service = Api.getClient.create(ApiService::class.java)
            val call = service.getMapList().execute()
            if (call.isSuccessful) {
                val mapListResponse = call.body()
                if (!mapListResponse!!.result.isNullOrEmpty()) {
                    val fileUrl = mapListResponse.result!![mapListResponse.result.size - 1].id
                    // getDownloadUrl(fileUrl!!)
                    val mapUrls = service.getDownloadMapURL(fileUrl!!).execute()
                    if (mapUrls.isSuccessful) {
                        val mapUrlsResponse = mapUrls.body()
                        if (!mapUrlsResponse!!.json_link.isNullOrEmpty()) {
                            val fileUrl = mapUrlsResponse.json_link
                            val map = service.downloadLatestMap(fileUrl)!!.execute()
                            if (map.isSuccessful) {
                                if (map.body() != null) {
                                  //  getMapFromUrl(map.body())
                                    try {
                                        val futureStudioIconFile =
                                            File(context.getExternalFilesDir(null), "euthopia.json")
                                        var inputStream: InputStream? = null;
                                        var outputStream: OutputStream? = null;
                                        try {
                                            val buffer = ByteArray(4096)
                                            var fileSizeDownloaded:Long = 0;
                                            inputStream = (map.body()!!.byteStream())
                                            outputStream = FileOutputStream(futureStudioIconFile);
                                            while (true) {
                                                val read = inputStream.read(buffer);
                                                if (read == -1) {
                                                    break;
                                                }
                                                outputStream.write(buffer, 0, read);
                                                fileSizeDownloaded += read
                                                setForeground(createForegroundInfo(AppUtils.getBytesString(fileSizeDownloaded)))

                                            }
                                            outputStream.flush();
                                            saveToDB()
                                        } catch (e: IOException) {
                                        } finally {
                                            if (inputStream != null) {
                                                inputStream.close();
                                            }
                                            if (outputStream != null) {
                                                outputStream.close();
                                            }
                                        }
                                    } catch (e: IOException) {
                                    }

                                }
                            }

                        }

                    }
                }

            }


            return Result.success()
        }


        private fun createForegroundInfo(progress: String): ForegroundInfo {
            val context = context
            val id = context.getString(R.string.notification_channel_id)
            val title = context.getString(R.string.notification_title)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            }
            val notification: Notification = NotificationCompat.Builder(context, id)
                .setContentTitle(title)
                .setTicker(title)
                .setContentText(progress)
                .setSmallIcon(R.drawable.logo)
                .setOngoing(true) // Add the cancel action to the notification which can
              .build()
            return ForegroundInfo(notification)
        }

    }

我正在关注本教程work manager codelab。我正在尝试从服务器下载JSON文件并将其保存到本地存储中。我不确定UI为何被阻止。在doWork()CoroutineWorker功能中将文件写入本地存储时。写入文件时,我正在显示通知的进度。该应用程序被卡住。

android android-architecture-components android-workmanager
2个回答
0
投票

此代码看起来不错,我相信您的问题不在这里,您可以看到使用此行doWork在哪个线程上运行Thread.currentThread().name函数(使用日志打印它),但我相信不会是主线程。因此您可能会阻塞主线程等待结果,但是我们需要更多代码才能知道。

您是否考虑过在这里使用RXJava / Kotlin?我认为在这种情况下会更简单。


0
投票

当您使用CoroutineWorker时,应在doWork()中像这样运行Dispatchers.IO协程范围中的所有代码:

class CoroutineDownloadWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {

    override val coroutineContext = Dispatchers.IO

    override suspend fun doWork(): Result = coroutineScope {
        val jobs = (0 until 100).map {
            async {
                downloadSynchronously("https://www.google.com")
            }
        }

        // awaitAll will throw an exception if a download fails, which CoroutineWorker will treat as a failure
        jobs.awaitAll()
        Result.success()
    }
}

该示例摘自:https://developer.android.com/topic/libraries/architecture/workmanager/advanced/coroutineworker

© www.soinside.com 2019 - 2024. All rights reserved.