android - 如何避免并行运行android Job?
问题描述
所以我有一个处理网络请求的 Android 作业。
这项工作可以通过多种方式开始,因此可以轻松并行运行,这对我不利。我想实现这一点,工作不会开始两次,或者如果它开始了,比在 try catch 块之前等待,直到第一个完成。
那么我怎样才能做到这一点,只有一个对象同时运行/运行。
我尝试添加 TAG 和 setUpdateCurrent false,但它没有做任何事情,所以当我开始两次工作时,它并行运行。之后我尝试了互斥锁,然后解锁。但它做了同样的事情。
使用互斥锁,我应该创建一个原子互斥锁,并通过 uniq 标签或 uuid 调用 lock?
好的,所以我弄清楚了我的互斥锁有什么问题,该作业每次都会创建一个新的互斥锁对象,所以它永远不会相同,也永远不会等待。
My Job:
class SendCertificatesJob @Inject constructor(
private val sendSync: SendSync,
private val sharedPreferences: SharedPreferences,
private val userLogger: UserLogger,
private val healthCheckApi: HealthCheckApi
) : Job(), CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO
private val countDownLatch = CountDownLatch(1)
private val mutex = Mutex()
override fun onRunJob(params: Params): Result {
var jobResult = Result.SUCCESS
if (!CommonUtils.isApiEnabled(context))
return jobResult
val notificationHelper = NotificationHelper(context)
var nb: NotificationCompat.Builder? = null
if (!params.isPeriodic) {
nb = notificationHelper.defaultNotificationBuilder.apply {
setContentTitle(context.resources.getString(R.string.sending_certificates))
.setTicker(context.resources.getString(R.string.sending_certificates))
.setOngoing(true)
.setProgress(0, 0, true)
.setSmallIcon(android.R.drawable.stat_notify_sync)
.setLargeIcon(
BitmapFactory.decodeResource(
context.resources,
R.mipmap.ic_launcher
)
)
}
notificationHelper.notify(NOTIFICATION_ID, nb)
jobCallback?.jobStart()
}
val failureCount = params.failureCount
if (failureCount >= 3) {
nb?.setOngoing(false)
?.setContentTitle(context.resources.getString(R.string.sending_certificates_failed))
?.setTicker(context.resources.getString(R.string.sending_certificates_failed))
?.setProgress(100, 100, false)
?.setSmallIcon(android.R.drawable.stat_sys_warning)
notificationHelper.notify(NOTIFICATION_ID, nb)
return Result.FAILURE
}
GlobalScope.launch(Dispatchers.IO) {
mutex.lock()
userLogger.writeLogToFile("SendCertificatesJob.onRunJob(), date:" + Calendar.getInstance().time)
try {
//Test
var doIt = true
var count =0
while (doIt){
Timber.d("SendSyncWorker: $count")
count++
delay(10000)
if(count == 12)
doIt = false
}
healthCheckApi.checkHealth(ApiModule.API_KEY).await()
try {
sendSync.syncRecordedClients()
} catch (e: Exception) {
e.printStackTrace()
}
val result = sendSync().forEachParallel2()
result.firstOrNull { it.second != null }?.let { throw Exception(it.second) }
val sb = StringBuilder()
if (nb != null) {
nb.setOngoing(false)
.setContentTitle(context.resources.getString(R.string.sending_certificates_succeeded))
.setTicker(context.resources.getString(R.string.sending_certificates_succeeded))
.setProgress(100, 100, false)
.setStyle(NotificationCompat.BigTextStyle().bigText(sb.toString()))
.setSmallIcon(android.R.drawable.stat_notify_sync_noanim)
notificationHelper.notify(NOTIFICATION_ID, nb)
jobCallback?.jobEnd()
}
sharedPreferences.edit().putLong(KEY_LATEST_CERTIFICATES_SEND_DATE, Date().time)
.apply()
} catch (e: Exception) {
Timber.tag(TAG).e(e)
if (nb != null) {
nb.setOngoing(false)
.setContentTitle(context.resources.getString(R.string.sending_certificates_failed))
.setTicker(context.resources.getString(R.string.sending_certificates_failed))
.setProgress(100, 100, false)
.setSmallIcon(android.R.drawable.stat_sys_warning)
notificationHelper.notify(NOTIFICATION_ID, nb)
jobCallback?.jobEnd()
}
jobResult = Result.RESCHEDULE
} finally {
countDownLatch.countDown()
mutex.unlock()
}
}
countDownLatch.await()
return jobResult
}
Job schedule:
fun scheduleNowAsync(_jobCallback: JobCallback? = null) {
jobCallback = _jobCallback
JobRequest.Builder(TAG_NOW)
.setExecutionWindow(1, 1)
.setBackoffCriteria(30000, JobRequest.BackoffPolicy.LINEAR)
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
.setRequirementsEnforced(true)
.setUpdateCurrent(true)
.build()
.scheduleAsync()
}
fun schedulePeriodicAsync() {
jobCallback = null
JobRequest.Builder(TAG)
.setPeriodic(900000)
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
.setRequirementsEnforced(true)
.setUpdateCurrent(true)
.build()
.scheduleAsync()
}
解决方案
我找到了解决我的问题的方法。
所以因为我使用匕首,我提供了一个单例互斥对象,并注入到工作中。当作业开始调用 mutex.lock() 时,由于互斥锁中只有一个对象,即使另一个作业开始,第二个作业也会等到第一个作业完成。
推荐阅读
- php - 如何让 Composer 从我的本地存储库自动安装包的所有依赖项?
- python - 在 Django 项目中获取 Page_not_found
- screen - 如何更改屏幕上显示的内容
- vba - 是否可以打开一个 URL(网页),然后使用 VBA 从 MS Access 打印它?
- xamarin.forms - Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol' 抛出异常
- docker - AZURE AKS 上的 HPA,但 pod 立即进入终止状态,因为它显示无法找到要挂载的默认卷
- ios - Facebook SDK设置广告客户跟踪启用不存在iOS14
- c - 有什么办法可以强制执行进程的基地址?
- go - 如何使用 go/analysis 找到 Ident 的声明?
- video - 将单个 scribe 文件转换为 mp4 或类似文件