await suspends computation fun processImage() = async { val deferred = loadImageAsync() val image = deferred.await() setImage(image) } await processImage processImage 2 1 loadImageAsync loadImageAsync
await suspends computation …and continues it when result is ready processImage 2 loadImageAsync fun processImage() = async { val deferred = loadImageAsync() processImage val image = deferred.await() 3 setImage(image) } loadImageAsync
await suspends computation …and continues it when result is ready processImage 2 loadImageAsync processImage 3 On which thread? loadImageAsync
Q: On which thread can the coroutine be continued? A: You specify that.
Continue in any thread from thread pool 1 async (CommonPool) { ... } 2 3 3
Continue in the UI thread UI 1 async ( UI ) { ... UI 2 } UI 3
Custom executor async (CustomContext) { ... } You can launch coroutine in the custom executor
Two asynchronous computations fun overlay(first: Image, second: Image): Image fun overlayAsync() = async (CommonPool) { val first = loadImageAsync ( "green" ) val second = loadImageAsync ( "red" ) overlay (first.await(), second.await()) } overlayAsync 1 3 2 overlayAsync overlayAsync
Programming with suspend functions
Q: Can I define my custom suspend functions? A: Yes.
Example: simple consecutive logic fun login(credentials: Credentials): UserID fun loadUserData(userID: UserID): UserData fun showData(data: UserData) fun showUserInfo(cred: Credentials) { val userID = login (credentials) val userData = loadUserData (userID) showData (userData) }
Rewrite with async/await fun login(credentials: Credentials): Deferred<UserID> fun loadUserData(userID: UserID): Deferred<UserData> fun showData(data: UserData) fun showUserInfo(credentials: Credentials) = async (CommonPool) { val userID = login (credentials).await() val userData = loadUserData (userID).await() showData (userData) }
Rewrite with suspend functions suspend fun login(credentials: Credentials): UserID suspend fun loadUserData(userID: UserID): UserData fun showData(data: UserData) suspend fun showUserInfo(credentials: Credentials) { val userID = login (credentials) val userData = loadUserData (userID) showData (userData) }
RxJava / CompletableFuture vs Coroutines
Rewrite with CompletableFuture fun loginAsync(credentials: Credentials): CompletableFuture<UserID> fun loadUserDataAsync(userID: UserID): CompletableFuture<UserData> fun showData(data: UserData) fun showUserInfo(credentials: Credentials) { loginAsync (credentials) .thenCompose { loadUserDataAsync ( it ) } .thenAccept { showData ( it ) } }
Rewrite with RxJava fun login(credentials: Credentials): Single<UserID> fun loadUserData(userID: UserID): Single<UserData> fun showData(data: UserData) fun showUserInfo(credentials: Credentials) { login (credentials) .flatMap { loadUserData ( it ) } .doOnSuccess { showData ( it ) } .subscribe() }
“Observables are great, but in many cases they’re kind of overkill.” somewhere on the Internet
RxJava & coroutines Reactive Kotlin Streams coroutines
kotlinx.coroutines async/await yield channels actors Library Language coroutines
Experimental status of Coroutines • We want the community to try it! • Migration aids will be provided • Old code will continue to work via the support library
kotlinx.coroutines • https://github.com/Kotlin/kotlinx.coroutines/ • Guide to kotlinx.coroutines by example • by Roman Elizarov (@relizarov)
Recommend
More recommend