In my Android app I want to use java.util.concurrent tools to make operations that return value (for educational purposes). I read that CompletableFuture can be used for this. I made a project where I simulate an operation that takes some time to execute:
class MyRepository {
private var counter = 0
// Here we make a blocking call
fun makeRequest(): Int {
Thread.sleep(2000L)
counter += 1
return counter
}
}
Then I call this function from UI thread:
fun getNumber(): Int {
val completableFuture = CompletableFuture<Int>()
Executors.newCachedThreadPool().submit<Any?> {
val result = myRepository.makeRequest()
completableFuture.complete(result)
null
}
return completableFuture.get()
}
The problem is that UI is blocked while this operation is being executed. How can I use CompletableFuture to make operation like this without blocking UI of application?
I want to use only java.util.concurrent tools for this.
To do asynchronous work using exclusively java.util.concurrent
, you should use an ExecutorService. And to return the value from your function you need to use a callback. And if you're working with UI, you need to provide a way to cancel work so callbacks won't try to work with your UI after its gone.
I think conventional behavior is to fire the callback on the Looper of the thread that called this function, or on the main looper as a fallback if it was called from a non-Looper thread.
private val executor = Executors.newFixedThreadPool(10)
// Call in onDestroy of UI
fun cancel() {
executor.shutdownNow()
}
fun getNumberThread(callback: (Int)->Unit) {
val looper = Looper.myLooper ?: Looper.mainLooper
val handler = Handler(looper)
val myCallable = MyCallable(myRepository)
executor.execute {
try {
val result = myCallable.call()
if (Thread.currentThread().isInterrupted()) return
handler.post { callback(result) }
} catch {e: MyException) {
if (Thread.currentThread().isInterrupted()) return
handler.post { callback(-1) } // if that's how you want to return error results
}
}
}