4. 4
Asynchronous code
Asynchronous code
essentially means
run some code not
sequentially
Eventually, the
way to run the
asynchronous
code is via
callbacks
Almost every
Android app has
asynchronous
code
6. 6
What are coroutines
Coroutines are piece
of code that can
suspend and resume
its execution at
certain locations.
The code inside
coroutine can be
expressed sequentially.
It's an old concept,
implemented by many
programming
languages.
Kotlin support
coroutines since
release 1.1 .
Most of the coroutines
related code that
JetBrains wrote is part
of their extensions
libraries of
kotlinx.coroutines .
In Kotlin you mark
function as coroutines
by the suspend
modifier, beside that
there is a minimal
code that supports
coroutines.
9. 9
Synchronous way
fun handleDeepLink(request: Request) : Response {
val response = Response()
….
response.journeyStartAddress =
request.addressFetcher.getAddressFromLatLan(request.journeyStartLatLng)
response.journeyEndAddress =
request.addressFetcher.getAddressFromLatLan(request.journeyStartLatLng)
….
return response
}
10. 10
Use-case 1: Make two network calls in parallel and wait for all
fun handleDeepLink(request: Request) : Response {
val response = Response()
val journeyStartJob = launch {
response.journeyStartAddress =
request.addressFetcher.getAddressFromLatLan(request.journeyStartLatLng)
}
val journeyEndJob = launch {
response.journeyEndAddress =
request.addressFetcher.getAddressFromLatLan(request.journeyStartLatLng)
}
runBlocking {
journeyStartJob.join()
journeyEndJob.join()
}
return response
}
11. 11
Use-case 2: Make two network calls in parallel and wait for first
fun handleDeepLink(request: Request) : Response {
val response = Response()
var firstAddress : String? = null
var secondAddress : String? = null
val firstAddressProvider = launch {
firstAddress = request.addressFetcher.getAddressFromLatLan(request.journeyStartLatLng)
}
val secondAddressProvider = launch {
secondAddress = request.addressFetcher.getAddressFromLatLan(request.journeyStartLatLng)
}
runBlocking {
response.journeyStartAddress = select<String> {
firstAddressProvider.onJoin {
firstAddress!!
}
secondAddressProvider.onJoin {
secondAddress!!
}
}
}
return response
}
12. 12
Use-case 3: Pre-fetch walking path
fun handleDeepLink(request: Request) : Response {
val response = Response()
val walkingInfoStream = BroadcastChannel<WalkingInfo>(Channel.CONFLATED)
response.walkingInfoStream = walkingInfoStream
launch {
walkingInfoStream.send(request.walkingInfoFetcher.fetch(request.journeyStartLatLng,
request.pickupLatLng))
}
return response
}
fun handleWalkingInfo(response: Response) {
val stream = response.walkingInfoStream.openSubscription()
stream.use {
launch {
val walkingInfo = it.receive()
showWalkingInfo(walkingInfo)
}
}
}
14. 14
Why to use coroutines
The code inside
coroutine can be
expressed
sequentially
Easy to write our
own abstraction
and adjust the use
of it to our
architecture
Kotlinx.coroutines
have out of the
box integration
with other major
frameworks like
RX 1 / 2, Java 8
stream and more
15. 15
But we have RX…. - if all you have is a hammer, everything looks like a nail
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()
}
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)
}