Skip to content

Instantly share code, notes, and snippets.

@webserveis
Forked from DenysZP/UseCase.kt
Created April 22, 2020 15:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save webserveis/8019ffba3acf39f9acca07e92ea704c8 to your computer and use it in GitHub Desktop.
Save webserveis/8019ffba3acf39f9acca07e92ea704c8 to your computer and use it in GitHub Desktop.
The implementation of the base UseCase with kotlin coroutines.
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext
abstract class UseCase<T, Params : Any> {
private lateinit var parentJob: Job
private lateinit var params: Params
private var isAttachedToLifecycle = false
private val backgroundContext: CoroutineContext = Dispatchers.IO
private val foregroundContext: CoroutineContext = Dispatchers.Main
fun withParams(params: Params) = this.also { it.params = params }
fun execute(useCaseListener: UseCaseListener<T>.() -> Unit) {
checkIsAttachedToLifecycle()
val listener = UseCaseListener<T>().apply { useCaseListener() }
cancel()
parentJob = Job()
CoroutineScope(foregroundContext + parentJob).launch {
listener(true)
try {
val result = withContext(backgroundContext) {
executeOnBackground()
}
listener(result)
} catch (cancellationException: CancellationException) {
listener(cancellationException)
} catch (e: Exception) {
listener(e)
} finally {
listener(false)
}
}
}
fun attachToLifecycle() {
isAttachedToLifecycle = true
}
fun cancel() {
if (this::parentJob.isInitialized) {
parentJob.apply {
cancelChildren()
cancel()
}
}
}
protected abstract suspend fun executeOnBackground(): T
protected fun getParams(): Params {
if (this::params.isInitialized) {
return params
} else {
throw RuntimeException(
"You have to initialize the required parameters " +
"of ${this.javaClass.name} before execute."
)
}
}
protected suspend fun <X> runAsync(
context: CoroutineContext = backgroundContext,
block: suspend () -> X
): Deferred<X> {
return CoroutineScope(context + parentJob).async {
block.invoke()
}
}
private fun checkIsAttachedToLifecycle() {
if (!isAttachedToLifecycle) {
throw RuntimeException("You have to attach ${this.javaClass.name} to the lifecycle.")
}
}
}
import kotlinx.coroutines.CancellationException
class UseCaseListener<T> {
private var onLoadingChange: ((Boolean) -> Unit)? = null
private var onComplete: ((T) -> Unit)? = null
private var onError: ((Throwable) -> Unit)? = null
private var onCancel: ((CancellationException) -> Unit)? = null
fun onLoadingChange(function: (Boolean) -> Unit) {
onLoadingChange = function
}
fun onComplete(function: (T) -> Unit) {
onComplete = function
}
fun onError(function: (Throwable) -> Unit) {
onError = function
}
fun onCancel(function: (CancellationException) -> Unit) {
onCancel = function
}
operator fun invoke(isLoading: Boolean) = onLoadingChange?.invoke(isLoading)
operator fun invoke(result: T) = onComplete?.invoke(result)
operator fun invoke(error: Throwable) = onError?.invoke(error)
operator fun invoke(error: CancellationException) = onCancel?.invoke(error)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment