fixed issues

This commit is contained in:
InsanusMokrassar 2021-01-03 12:45:38 +06:00
parent 3f132da62d
commit e04d14ccb1
2 changed files with 147 additions and 26 deletions

View File

@ -5,45 +5,68 @@ import androidx.work.*
import com.soywiz.klock.DateTime import com.soywiz.klock.DateTime
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
/**
* This method will enqueue [OneTimeWorkRequest] with [workName] and [existingWorkPolicy]. Use [setUpRequest] callback
* in case you need some additional actions to do before request will be enqueued
*/
suspend fun <T : KronSchedulerWork> Context.enqueueKronSchedulerWork( suspend fun <T : KronSchedulerWork> Context.enqueueKronSchedulerWork(
workName: String, workName: String,
delayMillis: Long, delayMillis: Long,
workClass: Class<T>, workClass: Class<T>,
setUpRequest: suspend OneTimeWorkRequest.Builder.() -> Unit existingWorkPolicy: ExistingWorkPolicy = ExistingWorkPolicy.REPLACE,
setUpRequest: suspend OneTimeWorkRequest.Builder.() -> Unit = {}
) = WorkManager.getInstance(applicationContext).enqueueUniqueWork( ) = WorkManager.getInstance(applicationContext).enqueueUniqueWork(
workName, workName,
ExistingWorkPolicy.REPLACE, existingWorkPolicy,
OneTimeWorkRequest.Builder(workClass).apply { OneTimeWorkRequest.Builder(workClass).apply {
setInitialDelay(delayMillis, TimeUnit.MILLISECONDS) setInitialDelay(delayMillis, TimeUnit.MILLISECONDS)
setUpRequest() setUpRequest()
}.build() }.build()
) )
/**
* This method is shortcut for [enqueueKronSchedulerWork] with reified [T] parameter
*/
suspend inline fun <reified T : KronSchedulerWork> Context.enqueueKronSchedulerWork( suspend inline fun <reified T : KronSchedulerWork> Context.enqueueKronSchedulerWork(
workName: String, workName: String,
delayMillis: Long, delayMillis: Long,
noinline setUpRequest: suspend OneTimeWorkRequest.Builder.() -> Unit existingWorkPolicy: ExistingWorkPolicy = ExistingWorkPolicy.REPLACE,
) = enqueueKronSchedulerWork(workName, delayMillis, T::class.java, setUpRequest) noinline setUpRequest: suspend OneTimeWorkRequest.Builder.() -> Unit = {}
) = enqueueKronSchedulerWork(workName, delayMillis, T::class.java, existingWorkPolicy, setUpRequest)
/**
* This method is shortcut for [enqueueKronSchedulerWork] with [initialScheduler]. It will try to calculate delay by
* itself. In case if [KronScheduler.next] of [initialScheduler] will return null, work WILL NOT be enqueued
*
* @return null in case if [KronScheduler.next] of [initialScheduler] has returned null and work has not been enqueued
*/
suspend fun <T : KronSchedulerWork> Context.enqueueKronSchedulerWork( suspend fun <T : KronSchedulerWork> Context.enqueueKronSchedulerWork(
workName: String, workName: String,
initialScheduler: KronScheduler, initialScheduler: KronScheduler,
workClass: Class<T>, workClass: Class<T>,
setUpRequest: suspend OneTimeWorkRequest.Builder.() -> Unit existingWorkPolicy: ExistingWorkPolicy = ExistingWorkPolicy.REPLACE,
setUpRequest: suspend OneTimeWorkRequest.Builder.() -> Unit = {}
): Operation? { ): Operation? {
val now = DateTime.now() val now = DateTime.now()
val nextTriggerTime = initialScheduler.next(now) val nextTriggerTime = initialScheduler.next(now)
val delayMillis = nextTriggerTime ?.minus(now) ?.millisecondsLong ?: return null val delayMillis = nextTriggerTime ?.minus(now) ?.millisecondsLong ?: return null
return enqueueKronSchedulerWork(workName, delayMillis, workClass, setUpRequest) return enqueueKronSchedulerWork(workName, delayMillis, workClass, existingWorkPolicy, setUpRequest)
} }
/**
* This method is shortcut for [enqueueKronSchedulerWork] with reified [T]
*/
suspend inline fun <reified T : KronSchedulerWork> Context.enqueueKronSchedulerWork( suspend inline fun <reified T : KronSchedulerWork> Context.enqueueKronSchedulerWork(
workName: String, workName: String,
initialScheduler: KronScheduler, initialScheduler: KronScheduler,
noinline setUpRequest: suspend OneTimeWorkRequest.Builder.() -> Unit existingWorkPolicy: ExistingWorkPolicy = ExistingWorkPolicy.REPLACE,
) = enqueueKronSchedulerWork(workName, initialScheduler, T::class.java, setUpRequest) noinline setUpRequest: suspend OneTimeWorkRequest.Builder.() -> Unit = {}
) = enqueueKronSchedulerWork(workName, initialScheduler, T::class.java, existingWorkPolicy, setUpRequest)
/** /**
* Use this class as an super class in case you wish to implement krontab-based enqueuing of works * Use this class as a super class in case you wish to implement krontab-based enqueuing of works
*
* @see enqueueKronSchedulerWork
* @see KrontabTemplateSchedulerWork
*/ */
abstract class KronSchedulerWork( abstract class KronSchedulerWork(
context: Context, context: Context,
@ -52,30 +75,59 @@ abstract class KronSchedulerWork(
context, context,
workerParams workerParams
) { ) {
/**
* This variable will be used to reorder new work after that one is happen
*
* @see prolongOnException
* @see prolongOnFailure
* @see prolongOnSuccess
*/
protected abstract val workName: String protected abstract val workName: String
protected open val prolongWork: Boolean = true
protected open val prolongOnFailure
get() = prolongWork
protected open val prolongOnException = false
protected open val prolongOnNextAbsent = false
/**
* Set this to false in case when this work must not be enqueued after successful complete
*/
protected open val prolongOnSuccess: Boolean = true
/**
* Set this to false in case when this work must not be enqueued after failure complete
*/
protected open val prolongOnFailure
get() = prolongOnSuccess
/**
* Set this to false in case when this work must not be enqueued after exception happen
*/
protected open val prolongOnException = false
/**
* [KronScheduler] of this method will be used to [prolong] this worker
*/
protected abstract suspend fun kronScheduler(): KronScheduler? protected abstract suspend fun kronScheduler(): KronScheduler?
/**
* This method is replacement of [doWork]. It is required to wrap work with [prolong]ing and handling of complete
* state
*/
protected abstract suspend fun onWork(): Result protected abstract suspend fun onWork(): Result
/**
* Override this method in case you have some additional settings for future [OneTimeWorkRequest]
*/
protected open suspend fun OneTimeWorkRequest.Builder.setUpRequest() {} protected open suspend fun OneTimeWorkRequest.Builder.setUpRequest() {}
/**
* This method will [enqueueKronSchedulerWork] using [workName], [kronScheduler] and default
* [ExistingWorkPolicy.REPLACE]. You can call this method in case you want to enqueue work by yourself, but you must
* be sure that you set up to false [prolongOnSuccess], [prolongOnFailure] and [prolongOnException]
*/
protected suspend fun prolong() { protected suspend fun prolong() {
val now = DateTime.now() applicationContext.enqueueKronSchedulerWork(
val nextTriggerTime = kronScheduler() ?.let { workName,
if (prolongOnNextAbsent) { kronScheduler() ?: return,
it.nextOrRelative(now) this::class.java
} else { ) {
it.next(now) setUpRequest()
} }
} }
val delayMillis = nextTriggerTime ?.minus(now) ?.millisecondsLong ?: return
applicationContext.enqueueKronSchedulerWork(workName, delayMillis, this::class.java) { setUpRequest() }
}
override suspend fun doWork(): Result { override suspend fun doWork(): Result {
val result = try { val result = try {
@ -86,8 +138,9 @@ abstract class KronSchedulerWork(
} }
throw e throw e
} }
if (result !is Result.Failure || prolongOnFailure) { when (result) {
prolong() is Result.Failure -> if (prolongOnFailure) prolong()
is Result.Success -> if (prolongOnSuccess) prolong()
} }
return result return result
} }

View File

@ -0,0 +1,68 @@
package dev.inmo.krontab
import android.content.Context
import androidx.work.*
const val krontabTemplateWorkField = "krontabTemplate"
/**
* Will [enqueueKronSchedulerWork] with [KronScheduler] from [krontabTemplate] and call [setUpRequest] on setting up
* [OneTimeWorkRequest.Builder] with [Data] which will be used to [OneTimeWorkRequest.Builder.setInputData] after
* [setUpRequest] completed
*/
suspend inline fun <reified T : KrontabTemplateSchedulerWork> Context.enqueueKrontabTemplateSchedulerWork(
workName: String,
krontabTemplate: KrontabTemplate,
existingWorkPolicy: ExistingWorkPolicy = ExistingWorkPolicy.REPLACE,
noinline setUpRequest: suspend OneTimeWorkRequest.Builder.(
data: Data
) -> Unit = {}
) = enqueueKronSchedulerWork(workName, krontabTemplate.toKronScheduler(), T::class.java, existingWorkPolicy) {
val data = workDataOf(
krontabTemplateWorkField to krontabTemplate
)
setUpRequest(data)
setInputData(data)
}
/**
* Extend this class in case you wish to base on [KrontabTemplate]. It will automatically handle request of
* [kronScheduler] and put it in [setUpRequest]
*/
abstract class KrontabTemplateSchedulerWork(
context: Context,
workerParams: WorkerParameters
) : KronSchedulerWork(context, workerParams) {
/**
* Will try to get [KrontabTemplate] from [getInputData] by key [krontabTemplateWorkField]
*
* @see setUpRequest
*/
protected val krontabTemplate: KrontabTemplate?
get() = inputData.getString(krontabTemplateWorkField)
/**
* Override this methods instead of old [setUpRequest] in case you wish to set up some work request parameters
*
* @param data This parameter will be used to put data inside of [OneTimeWorkRequest.Builder] after this method
* will be completed
*/
protected open suspend fun OneTimeWorkRequest.Builder.setUpRequest(data: Data) {}
/**
* Will automatically put [krontabTemplate] into work data, call [setUpRequest] with future [Data] object and then
* call [OneTimeWorkRequest.Builder.setInputData] with that [Data] object
*/
override suspend fun OneTimeWorkRequest.Builder.setUpRequest() {
val data = workDataOf(
krontabTemplateWorkField to krontabTemplate,
)
setUpRequest(data)
setInputData(data)
}
/**
* Will return [KronScheduler] in case if [krontabTemplate] was not null
*/
override suspend fun kronScheduler(): KronScheduler? = krontabTemplate ?.toKronScheduler()
}