2. - I am part of Tikal's Android group. We
meet, share, contribute and code
together on a monthly basis… We have
Tech radar, FuseDays, weekly lightning
talks, monthly meetups...
WHO AM I?
22. Regular synchronous query
fun query(): List<CallLogDao> {
val cursor = context.contentResolver.query(
CallLog.Calls.CONTENT_URI
null, null, null, null)
return queryAllLogs(cursor)
}
23. Reactive with SQL Brite
fun queryRxSqbrite(): Observable<List<CallLogDao>> {
return sqBriteResolver.createQuery(
CallLog.Calls.CONTENT_URI,
null, null, null, null, false)
.mapToList({
c -> CallLogDao(c)
}).firstElement().toObservable()
}
24. Consuming rx Observable
@Test
fun testRxSqBrite() {
val latch = CountDownLatch(1)
var gotList = ArrayList<CallLogDao> ()
manager.queryRxSqbrite().subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
list: List<CallLogDao> ->
gotList.addAll( list)
latch.countDown()
})
latch.await()
assertTrue("got some logs", gotList.size > 0)
}
25. What are coroutines?
Light weight way of asynchronously execute
computations that can be suspended without
blocking the thread
26. How are they different than
threads?
● Much lighter than threads
● Suspending is not blocking
● Millions of coroutines can run in one thread
● Less context switch overhead
● Less memory overhead
27. Trivial example
suspend fun doALongQuery() { … }
suspend fun processResults() { … }
suspend fun uploadResultsToServer() { … }
fun saveSessionStatus(status) { … }
suspend fun doALotOfWork() {
val queryResult = doALongQuery()
val processedResults = processResults(queryResult)
val status = uploadResultsToServer(processedResults)
saveSessionStatus(status)
}
28. Coroutine builder
fun doALotOfWork() {
launch(UI) {
val queryResult = doALongQuery()
val processedResults = processResults(queryResult)
val status = uploadResultsToServer(processedResults)
saveSessionStatus(status)
}
}
29. Async with Anko coroutines
fun queryAsyncAnko() : Deferred<List<CallLogDao>>? {
val cursor = context.contentResolver.query(
CallLog.Calls.CONTENT_URI,
null, null, null, null)
return bg {
queryAllLogs(cursor)
}
} else {
return null
}
}
30. Consuming Anko deferred
@Test
fun testAsyncAnko() {
val deferredLogs = manager.queryAsyncAnko()
assertNotNull("is it null", deferredLogs?.await())
assertTrue("got some?", actualLogs!!.size > 0)
}
31. How do coroutines work?
Not a new JVM feature, implemented via compile
time bytecode changes.
32. Code turned into a state machine
When compiling, suspension points are inserted
into the code.
When suspended, state and variables are saved
and serialized.
Suspended coroutine is called continuation.
37. What about Rx?
● Experimental lib, kotlinx coroutines reactive
● Wrappers for Reactive Streams, Reactor,
RxJava 1.x and RxJava 2.x using coroutines
● Under heavy development, and very
experimental
● At the time of writing, version is 0.18
38. Current status
IMPORTANT NOTE: We advise library authors to follow the
same convention: add the "experimental" (e.g.
com.example.experimental) suffix to your packages exposing
coroutine-based APIs so that your library remains binary
compatible. When the final API is released, follow these steps:
39. Rx2 example: flowable
return rxFlowable(coroutineContext) {
if (cursor.moveToFirst()) {
do {
send(CallLogDao(cursor))
} while (cursor.moveToNext())
}
}
40. Consuming rx2 Flowable
@Test
fun testRx2Coroutines() = runBlocking {
val source = manager.queryRxCoroutines(coroutineContext)
if (source != null) {
var success = false
source.observeOn(Schedulers.io(), false, 10)
.doOnComplete {
success = true
}
.subscribe {
log -> Log.d(TAG, "got " + log.toString())
} }
source.awaitLast()
assertTrue("got published via RX", success)
} else {
assertTrue("failed to generate RX stream", false)
}
}
41. But what is this coroutineContext?
Most important part is that they include a
coroutine dispatcher which determines on what
threads can the coroutine be executed.
They can be specified, or parent context can be
used.
42. Coroutine children
When a croutine is launched with context of
another coroutine, it becomes its child.
When a parent is cancelled, all of its children are
cancelled.
43. Waiting in coroutine context
If Thread.sleep(), CountdownLatch or similar
mechanism is used, it blocks the thread,
therefore coroutine does not get executed.
Instead use suspending, such as await, delay, or
similar.