这是我的工人班:
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
功能中将文件写入本地存储时。写入文件时,我正在显示通知的进度。该应用程序被卡住。
此代码看起来不错,我相信您的问题不在这里,您可以看到使用此行doWork
在哪个线程上运行Thread.currentThread().name
函数(使用日志打印它),但我相信不会是主线程。因此您可能会阻塞主线程等待结果,但是我们需要更多代码才能知道。
您是否考虑过在这里使用RXJava / Kotlin?我认为在这种情况下会更简单。
当您使用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