Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save duangsuse/dfc532a16f547459bcf3f4f8d922d849 to your computer and use it in GitHub Desktop.
Save duangsuse/dfc532a16f547459bcf3f4f8d922d849 to your computer and use it in GitHub Desktop.
Essay: Android cancellable asynchronous task API abstractoin in Kotlin
package org.duangsuse.essay.android.Async
import android.os.AsyncTask
/**
* Job to be executed in worker thread, returning result with type `R`
*/
@FunctionalInterface
interface BackgroundJob<out R> {
/**
* Logic to launch in worker thread
*/
@Throws(Throwable::class)
fun doInBackground(): R
}
/**
* `BackgroundJob` lifecycle events
*/
sealed class JobLifecycleEvent<out T> {
/**
* Task lifecycle event handler
*/
@FunctionalInterface
interface Handler<T> {
fun handleEvent(ev: JobLifecycleEvent<T>)
}
/**
* Task started event
*/
object StartEvent : JobLifecycleEvent<Nothing>()
/**
* Task finished event
*/
class ResultEvent<T>(val result: T) : JobLifecycleEvent<T>()
/**
* Task error event
*/
class ErrorEvent(val error: Throwable) : JobLifecycleEvent<Nothing>()
}
/**
* Cancellable task
*/
interface Cancellable {
/**
* Cancel this task, if not cancelled
*/
fun cancel()
/**
* Is this task cancelled?
*/
fun isCancelled(): Boolean
}
/**
* Group combination of cancellable task
*/
class CancellableGroup(private val cs: Set<Cancellable> = mutableSetOf()): Set<Cancellable> by cs, Cancellable {
override fun isCancelled(): Boolean = cs.all(Cancellable::isCancelled)
override fun cancel() = cs.forEach(Cancellable::cancel)
}
/**
* Android `AsyncTask` Cancellable
*/
class AsyncTaskCancellable<T, R>(private val task: AsyncTask<in T, *, out R>): Cancellable {
override fun cancel() { if (!isCancelled()) task.cancel(true) }
override fun isCancelled(): Boolean = task.isCancelled
}
/**
* Android AsyncTask Abstraction
*/
object Async {
/**
* Launch an asynchronous task, with given listener, returning cancellable token
*/
fun <R> launchAsyncCancellable(job: BackgroundJob<R>, listener: JobLifecycleEvent.Handler<R>): Cancellable {
val task = object : AsyncTask<Nothing?, Nothing, R?>() {
override fun onPreExecute() = listener.handleEvent(JobLifecycleEvent.StartEvent)
override fun doInBackground(vararg params: Nothing?): R? {
try { return job.doInBackground() }
catch (ex: Throwable) { listener.handleEvent(JobLifecycleEvent.ErrorEvent(ex)) }
return null
}
override fun onPostExecute(result: R?) { result?.let { listener.handleEvent(JobLifecycleEvent.ResultEvent(it)) } }
}
return AsyncTaskCancellable(task).also { task.execute() }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment