1## Asynchronous work {#async} 2 3### With return values {#async-return} 4 5#### Kotlin 6 7Traditionally, asynchronous work on Android that results in an output value 8would use a callback; however, better alternatives exist for libraries. 9 10Kotlin libraries should consider 11[coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) and 12`suspend` functions for APIs according to the following rules, but please refer 13to the guidance on [allowable dependencies](#dependencies-coroutines) before 14adding a new dependency on coroutines. 15 16Kotlin suspend fun vs blocking | Behavior 17------------------------------------ | -------------------------- 18blocking function with @WorkerThread | API is blocking 19suspend | API is async (e.g. Future) 20 21In general, do not introduce a suspend function entirely to switch threads for 22blocking calls. To do so correctly requires that we allow the developer to 23configure the Dispatcher. As there is already a coroutines-based API for 24changing dispatchers (withContext) that the caller may use to switch threads, it 25is unecessary API overhead to provide a duplicate mechanism. In addition, it 26unecessary limits callers to coroutine contexts. 27 28```kotlin 29// DO expose blocking calls as blocking calls 30@WorkerThread 31fun blockingCall() 32 33// DON'T wrap in suspend functions (only to switch threads) 34suspend fun blockingCallWrappedInSuspend( 35 dispatcher: CoroutineDispatcher = Dispatchers.Default 36) = withContext(dispatcher) { /* ... */ } 37 38// DO expose async calls as suspend funs 39suspend fun asyncCall(): ReturnValue 40 41// DON'T expose async calls as a callback-based API (for the main API) 42fun asyncCall(executor: Executor, callback: (ReturnValue) -> Unit) 43``` 44 45#### Java 46 47Java libraries should prefer `ListenableFuture` and the 48[`CallbackToFutureAdapter`](https://developer.android.com/reference/androidx/concurrent/futures/CallbackToFutureAdapter) 49implementation provided by the `androidx.concurrent:concurrent-futures` library. 50Functions and methods that return `ListenableFuture` should be suffixed by, 51`Async` to reserve the shorter, unmodified name for a `suspend` method or 52extension function in Kotlin that returns the value normally in accordance with 53structured concurrency. 54 55Libraries **must not** use `java.util.concurrent.CompletableFuture`, as it has a 56large API surface that permits arbitrary mutation of the future's value and has 57error-prone defaults. 58 59See the [Dependencies](#dependencies) section for more information on using 60Kotlin coroutines and Guava in your library. 61 62### Cancellation 63 64Libraries that expose APIs for performing asynchronous work should support 65cancellation. There are *very few* cases where it is not feasible to support 66cancellation. 67 68Libraries that use `ListenableFuture` must be careful to follow the exact 69specification of 70[`Future.cancel(boolean mayInterruptIfRunning)`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html?is-external=true#cancel-boolean-) 71behavior. 72 73```java {.bad} 74@Override 75public boolean cancel(boolean mayInterruptIfRunning) { 76 // Does not support cancellation. 77 return false; 78} 79``` 80 81```java {.bad} 82@Override 83public boolean cancel(boolean mayInterruptIfRunning) { 84 // Aggressively does not support cancellation. 85 throw new UnsupportedOperationException(); 86} 87``` 88 89```java {.good} 90@Override 91public boolean cancel(boolean mayInterruptIfRunning) { 92 // Pseudocode that ignores threading but follows the spec. 93 if (mCompleted 94 || mCancelled 95 || mRunning && !mayInterruptIfRunning) { 96 return false; 97 } 98 mCancelled = true; 99 return true; 100} 101``` 102 103### Avoid `synchronized` methods 104 105Whenever multiple threads are interacting with shared (mutable) references those 106reads and writes must be synchronized in some way. However synchronized blocks 107make your code thread-safe at the expense of concurrent execution. Any time 108execution enters a synchronized block or method any other thread trying to enter 109a synchronized block on the same object has to wait; even if in practice the 110operations are unrelated (e.g. they interact with different fields). This can 111dramatically reduce the benefit of trying to write multi-threaded code in the 112first place. 113 114Locking with synchronized is a heavyweight form of ensuring ordering between 115threads, and there are a number of common APIs and patterns that you can use 116that are more lightweight, depending on your use case: 117 118* Compute a value once and make it available to all threads 119* Update Set and Map data structures across threads 120* Allow a group of threads to process a stream of data concurrently 121* Provide instances of a non-thread-safe type to multiple threads 122* Update a value from multiple threads atomically 123* Maintain granular control of your concurrency invariants 124