Created
March 28, 2019 12:06
-
-
Save DenysZP/da1dc69454808812a831bb863156cf84 to your computer and use it in GitHub Desktop.
The implementation of the base UseCase with kotlin coroutines.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.") | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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