A simple implementation of Futures in Kotlin
MIT License
A simple implementation of Futures in Kotlin. Has very minimal dependencies, so you can use it on Android.
Add my bintray repo as a maven repository:
repositories {
maven {
url "https://dl.bintray.com/rahulrav/kotlin-futures/"
}
}
and then add the library as a dependency:
dependencies {
compile "com.rahulrav:com.rahulrav.futures:1.2.0"
}
Creating a Future
is really easy.
import com.rahulrav.futures.Future
val future: Future<Int> = Future.submit {
// fake some long running computation
Thread.sleep(1000)
10
}
This future supports combinators like map
and flatMap
so you can transform and flatten Future
's.
val response: Future<HttpResponse> = someLongRunningComputation()
val headers: Future<List<Pair<String, String>>> = response.map { result ->
result.headers
}
To flatten results of asynchronous computations use flatMap
.
val first: Future<Int> = someLongRunningComputation()
val result: Future<Double> = first.flatMap { result ->
val second: Future<Double> = anotherLongRunningComputation(result)
// we are returning a Future<Double> instead of a Future<Future<Double>>
second
}
Futures work on Android. However, one important thing to note is there might be operations that you might want to run on the UI thread instead of the default executor. In such cases, all you need to do is to provide an implementation
of the Executor
that uses a Looper
. Here is an example of how you could do that:
import android.os.Handler
import android.os.Looper
import java.util.concurrent.Executor
class DefaultExecutors {
companion object {
val handler = lazy {
Handler(Looper.getMainLooper())
}
/** Submits things on the UI Thread. */
val UiExecutor = Executor({ command ->
handler.value.post(command)
})
}
}
val future: Future<Int> = Future.submit {
// fake some long running computation
Thread.sleep(1000)
10
}
future.map(DefaultExecutors.UiExecutor) {
// this sub-task now runs on the main looper
}
When using the Kotlin Futures library you need to be careful about returing null
or optional values.
This is because, the implementation of the library expects the caller to provide non-null values.
Warning: If you attempt to resolve a Future
with a null
value, it will never get resolved.
You should wrap your optional type with something like:
sealed class Optional<T> {
class Some<T>(val contents: T): Optional<T>()
object None
}
If you are using JDK 8, you should use the Optional type.
This library now has experimental support for Kotlin Coroutines. Here is an example on how you can use coroutines.
import com.rahulrav.futures.experimental.CoroutineSupport.await
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.launch
val future = Future.submit {
Thread.sleep(100)
10
}
launch(CommonPool) {
val result = future.await()
println("Coroutine support: The result is $result")
}