Walmyr Carvalho
#AndroidMeetupSP
Android + Kotlin Coroutines
Async de um jeito "diferente"
+
Slide 2
Slide 2 text
Walmyr Carvalho
@walmyrcarvalho
Slide 3
Slide 3 text
No content
Slide 4
Slide 4 text
Contexto
Slide 5
Slide 5 text
Aplicações modernas para Android
vão precisar fazer uso de alguma
operação assíncrona em algum momento.
Slide 6
Slide 6 text
No content
Slide 7
Slide 7 text
E temos algumas várias (muitas)
formas de se fazer isso,
cada uma com um propósito:
Slide 8
Slide 8 text
AsyncTask
Loader
Service
JobScheduler/JobSchedulerCompat
IntentService
Thread
FutureTask
Firebase JobDispatcher
Slide 9
Slide 9 text
E hoje temos uma biblioteca “vencedora” no que diz
respeito a operações assíncronas no Android em geral.
Slide 10
Slide 10 text
No content
Slide 11
Slide 11 text
Resumindo:
Temos muitas opções mas todas elas tem algum ponto
"negativo” em algum aspecto.
Slide 12
Slide 12 text
Kotlin Coroutines
Slide 13
Slide 13 text
Coroutines no Kotlin são threads "mais leves”,
com uma sintaxe de código assíncrono tão
direta quanto a de um código síncrono.
Slide 14
Slide 14 text
Elas são tipos de funções chamadas suspending functions,
e tem seus métodos marcados com a palavra chave suspend.
Slide 15
Slide 15 text
suspend fun getUser(userId: String): User {
// return an User object
}
Slide 16
Slide 16 text
Na prática, a utilização duma coroutine seria:
Slide 17
Slide 17 text
// roda o código em uma thread pool em background
fun asyncOverlay() = async(CommonPool) {
// inicia duas operações assíncronas
val original = asyncLoadImage("original")
val overlay = asyncLoadImage("overlay")
// e aplica o overlay para os dois resultados
applyOverlay(original.await(), overlay.await())
}
// executa a coroutine no contexto de UI
launch(UI) {
val image = asyncOverlay().await()
showImage(image)
}
Slide 18
Slide 18 text
O launch é a maneira mais simples de se criar uma coroutine
numa thread em background, tendo um Job (uma task em
background, basicamente) como sua referência para si.
Slide 19
Slide 19 text
public actual fun launch(
context: CoroutineContext = DefaultDispatcher,
start: CoroutineStart = CoroutineStart.DEFAULT,
parent: Job? = null,
block: suspend CoroutineScope.() -> Unit
): Job
Slide 20
Slide 20 text
Conceitualmente, o async é similar ao launch,
mas a diferença deles é que o async retorna um Deferred,
que é basicamente uma future (ou promise).
Slide 21
Slide 21 text
public actual fun async(
context: CoroutineContext = DefaultDispatcher,
start: CoroutineStart = CoroutineStart.DEFAULT,
parent: Job? = null,
block: suspend CoroutineScope.() -> T
): Deferred
Slide 22
Slide 22 text
O CoroutineContext diz respeito a qual thread ela irá
rodar: background (CommonPool) ou UI.
Slide 23
Slide 23 text
Tecnicamente, um Deferred é um Job, só que com uma
future com uma promessa de entregar um valor em breve.
Slide 24
Slide 24 text
Ou seja: No async você tem a mesma
funcionalidade do launch, mas com a diferença
que ele retorna um valor no .await():
Slide 25
Slide 25 text
fun getUser(userId: String): User = async {
// return User
}
launch(UI) {
val user = getUser(id).await()
navigateToUserDetail(user)
}
Slide 26
Slide 26 text
Também é possível rodar alguma operação bloqueando
completamente a thread, utilizando o runBlocking,
mas não é algo muito necessário no Android:
Slide 27
Slide 27 text
runBlocking {
delay(2000)
}
Slide 28
Slide 28 text
Resumindo:
Se não faço questão de um callback -> launch
Se eu preciso esperar uma future (Deferred) -> async
Se eu preciso bloquear minha thread -> runBlocking
Slide 29
Slide 29 text
Também é possível cancelar um Job (ou um Deferred),
e checar o estado dele:
Slide 30
Slide 30 text
val job = launch {
// do your stuff
}
job.cancel()
val job = launch {
while (isActive){
//do your stuff
}
}