SlideShare a Scribd company logo
Coroutines & Jetpack
Aplicações assíncronas no Android com
Nelson Glauber
@nglauber

slideshare.com/nglauber

youtube.com/nglauber
A main thread do Android
• Carregar arquivo de layout

• Desenhar as views

• Tratar os eventos de UI

• …
A main thread do Android
A main thread do Android
Solução?
Async no Android
• AsyncTask !

• Thread + Handler "

• Loaders (deprecated) !

• Volley #$

• RxJava 🧐
Coroutines
• Essencialmente, coroutines são light-weight threads. 

• Fácil de usar (sem mais "callbacks hell” e/ou centenas de
operadores).

• Úteis para operações de I/O ou qualquer outra tarefa
computacional mais onerosa.

• Permite a substituição de callbacks por operações
assíncronas.
Dependências
dependencies {
def coroutines_version = '1.2.1'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
...
}
suspend
• Suspending functions são o centro de tudo em Coroutines.
Elas são basicamente funções que podem ser pausadas e
retomadas após algum tempo. 

• Podem executar longas tarefas e aguardar o resultado sem
bloquear a thread atual.

• A sintaxe é idêntica a uma função “normal”, exceto pela
adição da palavra reservada suspend.

• Por si só, uma suspending function não é assíncrona.

• Só pode ser chamada a partir de outra suspending function.
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.Assert.assertEquals
class CalculatorUnitTest {
@Test
fun sum_isCorrect() = runBlocking {
val calc = Calculator()
assertEquals(4, calc.sum(2, 2))
}
}
import kotlinx.coroutines.delay
class Calculator {
suspend fun sum(a: Int, b: Int): Int {
delay(5_000)
return a + b
}
}
Coroutines no Android
• Para entendermos melhor as Coroutines no Android
precisamos falar de 4 conceitos:

• Job

• Context

• Scope

• Dispatcher
class MainActivity : AppCompatActivity() {
private val job = Job()
private val coroutineScope = CoroutineScope(job + Dispatchers.Main)
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
fun callWebService() {
coroutineScope.launch {
txtOutput.text = ""
val books = withContext(Dispatchers.IO) {
BookHttp.loadBooks()
}
books?.forEach {
txtOutput.append("${it.title}n")
}
}
}
...
class MainActivity : AppCompatActivity() {
private val job = Job()
private val coroutineScope = CoroutineScope(job + Dispatchers.Main)
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
fun callWebService() {
coroutineScope.launch {
txtOutput.text = ""
val books = withContext(Dispatchers.IO) {
BookHttp.loadBooks()
}
books?.forEach {
txtOutput.append("${it.title}n")
}
}
}
...
Job
• Um Job representa uma tarefa ou conjunto de
tarefas em background.

• A função launch retorna um Job.

• Mantém a referência do código que está em
execução.

• Pode possuir “filhos”.

• Pode ser cancelado usando a função cancel.
class MainActivity : AppCompatActivity() {
private val job = Job()
private val coroutineScope = CoroutineScope(job + Dispatchers.Main)
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
fun callWebService() {
coroutineScope.launch {
txtOutput.text = ""
val books = withContext(Dispatchers.IO) {
BookHttp.loadBooks()
}
books?.forEach {
txtOutput.append("${it.title}n")
}
}
}
...
Context
• É um conjunto de atributos que configuram
uma coroutine. 

• Representada pela interface
CoroutineContext.

• Pode definir a política de threading,
tratamento de exceções, etc.
class MainActivity : AppCompatActivity() {
private val job = Job()
private val coroutineScope = CoroutineScope(job + Dispatchers.Main)
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
fun callWebService() {
coroutineScope.launch {
txtOutput.text = ""
val books = withContext(Dispatchers.IO) {
BookHttp.loadBooks()
}
books?.forEach {
txtOutput.append("${it.title}n")
}
}
}
...
Scope
• Um escopo serve como uma espécie de ciclo de
vida para um conjunto de coroutines.

• Coroutines sempre rodam em um escopo.

• Permite um maior controle das tarefas em
execução
GlobalScope
• O GlobalScope, como o nome sugere, é utilizado em tarefas cujo o escopo é
global da aplicação.

• O GlobalScope é considerado um anti-pattern no Android e deve ser evitado.
private suspend fun loadName(): String {
delay(5000)
return "Glauber"
}
private fun firstCoroutine() {
GlobalScope.launch {
val name = loadName()
println("$name!")
}
println("Hello, ")
}
class MainActivity : AppCompatActivity() {
private val job = Job()
private val coroutineScope = CoroutineScope(job + Dispatchers.Main)
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
fun callWebService() {
coroutineScope.launch {
txtOutput.text = ""
val books = withContext(Dispatchers.IO) {
BookHttp.loadBooks()
}
books?.forEach {
txtOutput.append("${it.title}n")
}
}
}
...
Dispatcher
• Um dispatcher define o pool de threads
que a coroutine executará.

• Default - É otimizado para processos
que usam a CPU mais intensamente.

• IO - recomendado para tarefas de rede
ou arquivos. O pool de threads é
compartilhado com o dispatcher
DEFAULT.

• Main - main thread do Android.
fun callWebService() {
coroutineScope.launch {
txtOutput.text = ""
val books = withContext(Dispatchers.IO) {
BookHttp.loadBooks()
}
books?.forEach {
addTextToTextView("${it.title}n")
}
}
}
&
fun callWebService() {
coroutineScope.launch {
txtOutput.text = ""
val books = BookHttp.loadBooks()
books?.forEach {
txtOutput.append("${it.title}n")
}
}
}
android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1513)
at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:117)
at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:105)
at java.net.InetAddress.getAllByName(InetAddress.java:1154)
at com.android.okhttp.Dns$1.lookup(Dns.java:39)
FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: br.com.nglauber.coroutinesdemo, PID: 26507
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that
created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7753)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1225)
fun callWebService() {
coroutineScope.launch(Dispatchers.IO){
txtOutput.text = ""
val books = BookHttp.loadBooks()
books?.forEach {
txtOutput.append("${it.title}n")
}
}
}
class MainActivity : AppCompatActivity() {
private val job = Job()
private val coroutineScope = CoroutineScope(job + Dispatchers.Main)
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
fun callWebService() {
coroutineScope.launch {
txtOutput.text = ""
val books = withContext(Dispatchers.IO) {
BookHttp.loadBooks()
}
books?.forEach {
txtOutput.append("${it.title}n")
}
}
}
...
class MainActivity : AppCompatActivity(), CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
fun callWebService() {
launch {
txtOutput.text = ""
val books = withContext(Dispatchers.IO) {
BookHttp.loadBooks()
}
books?.forEach {
txtOutput.append("${it.title}n")
}
}
}
...
Lifecycle
Lifecycle Scope
• Escopo atrelado ao ciclo de vida da Activity, Fragment ou
View do Fragment

• Além da função launch, podemos usar o
launchWhenCreated, launchWhenStarted e
launchWhenResumed.
dependencies {
...
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha01"
}
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
lifecycleScope.launch {
...
}
// or...
lifecycleScope.launchWhenCreated {
...
}
// or...
lifecycleScope.launchWhenStarted {
...
}
}
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
lifecycleScope.launch {
...
}
// or...
lifecycleScope.launchWhenCreated {
...
}
// or...
lifecycleScope.launchWhenStarted {
...
}
}
class MyFragment: Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewLifecycleOwner.lifecycleScope.launch {
...
}
}
}
ViewModel
ViewModel Scope




Um ViewModel agora possui a propriedade viewModelScope.
dependencies {
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0-alpha01"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-alpha01"
testImplementation "androidx.arch.core:core-testing:2.1.0-beta01"
}
class MainViewModel : ViewModel() {
private val _message = MutableLiveData<String>()
val message: LiveData<String> = _message
fun loadMessage() {
viewModelScope.launch {
val message = withContext(Dispatchers.IO) {
loadMessageFromNetwork()
}
_message.value = message
}
}
private suspend fun loadMessageFromNetwork() : String {
delay(2_000)
return "Hello from ViewModel"
}
}
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by lazy {
ViewModelProviders.of(this).get(MainViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
...
viewModel.message.observe(this, Observer { s ->
txtOutput.text = s
})
viewModel.loadMessage()
}
...
WorkManager
WorkManager
dependencies {
def work_version = "2.1.0-beta02"
implementation "androidx.work:work-runtime-ktx:$work_version"
androidTestImplementation "androidx.work:work-testing:$work_version"
}
class MyWork(context: Context, params: WorkerParameters) :
CoroutineWorker(context, params) {
override suspend fun doWork(): Result = try {
val output = inputData.run {
val x = getInt("x", 0)
val y = getInt("y", 0)
val result = Calculator().sum(x, y)
workDataOf("result" to result)
}
Result.success(output)
} catch (error: Throwable) {
Result.failure()
}
}
private fun callMyWork() {
val request =
OneTimeWorkRequestBuilder<MyWork>()
.setInputData(workDataOf("x" to 84, "y" to 12))
.build()
WorkManager.getInstance(this).run {
enqueue(request)
getWorkInfoByIdLiveData(request.id)
.observe(this@MainActivity, Observer {
if (it.state == WorkInfo.State.SUCCEEDED) {
val result = it.outputData.getInt("result", 0)
addTextToTextView("Result-> $result")
}
})
}
voltando às coroutines…
Iniciando uma coroutine
• As duas formas de iniciar uma coroutine são:

• A função launch é uma “fire and forget”  que significa
que não retornará o resultado para que a chamou (mas
retornará um Job).

• A função async retorna um objeto Deferred que permite
obter o seu resultado.
launch = Sequencial
private fun sequentialCalls() {
txtOutput.text = ""
launch {
val time = measureTimeMillis {
val one = doSomethingUsefulOne()
val two = doSomethingUsefulTwo()
addTextToTextView("The answer is ${one + two}")
}
addTextToTextView("Completed in $time ms")
}
}
The answer is 42

Completed in 2030 ms
async = Paralelo
private fun parallelCalls() {
txtOutput.text = ""
launch {
val time = measureTimeMillis {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
addTextToTextView("The answer is ${one.await() + two.await()} ")
}
addTextToTextView("Completed in $time ms")
}
}
The answer is 42

Completed in 1038 ms
Launch x Async
Em quase todos os casos, deve-se usar a função
launch para iniciar uma coroutine a partir de uma
função “normal”. 

Uma função comum não pode chamar o await
(porque ela é uma suspending function), então
não faz muito sentido usar o async como ponto
de partida.
Exceptions
• As exceções tem comportamentos diferentes para o
launch e o async. 
Exceptions - launch
private fun handlingException() {
launch {
txtOutput.text = ""
try {
val a = methodThatThrowsException()
addTextToTextView("Ok ${a}")
} catch (e: Exception) {
addTextToTextView("handlingException caught: ${e.message}")
}
}
}
Exceptions - async
private fun handlingAsyncException() {
launch {
txtOutput.text = ""
try {
val task = async { throwingException() }
addTextToTextView("Ok ${task.await()}")
} catch (e: Exception) {
addTextToTextView("handlingAsyncException caught: ${e}")
}
}
}
Exceptions - async #1
private fun handlingAsyncException1() {
launch {
txtOutput.text = ""
val task = async(SupervisorJob(job)) {
methodThatThrowsException()
}
try {
addTextToTextView("Ok ${task.await()}")
} catch (e: Throwable) {
addTextToTextView("Erro! ${e.message}")
}
}
}
Exceptions - async #2
private fun handlingAsyncException2() {
launch {
txtOutput.text = ""
supervisorScope {
val task = async { methodThatThrowsException() }
try {
addTextToTextView("Ok ${task.await()}")
} catch (e: Throwable) {
addTextToTextView("Erro! ${e.message}")
}
}
}
}
Exceptions - async #3
private fun handlingAsyncException3() {
launch {
txtOutput.text = ""
try {
coroutineScope {
val task = async {
methodThatThrowsException()
}
addTextToTextView("Ok ${task.await()}")
}
} catch (e: Throwable) {
addTextToTextView("Erro! ${e.message}")
}
}
}
Cancelamento
• Para cancelar um job, basta chamar o método cancel.

• Uma vez cancelado o job não pode ser reusado.

• Para cancelar os jobs filhos, use cancelChildren.

• A propriedade isActive indica que o job está em
execução, isCancelled cancelado, e isCompleted
terminou sua execução.

• Se cancelado enquanto suspenso, levanta
CancellationException.
private fun cancelDemo() {
val startTime = System.currentTimeMillis()
longJob = launch(Dispatchers.Default) {
var nextPrintTime = startTime
var i = 0
while (i < 20 && isActive) { // this == CoroutineScope, que possui isActive
if (System.currentTimeMillis() >= nextPrintTime) {
Log.d("NGVL","job: I'm sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
}
private fun nonCancellableJob() {
nonCancellableJob = launch {
withContext(NonCancellable) {
println("job: I'm here")
delay(5000L)
println("job: I'm non-cancellable")
}
}
}
withTimeout
• Executa uma coroutine levantando uma
TimeoutCancellationException	caso sua duração
exceda o timeout especificado.

• Uma vez que o cancelamento é apenas uma exceção, é
possível trata-la facilmente.

• É possível usar a função withTimeoutOrNull que é similar
a withTimeout, mas retorna null ao invés de levantar a
exceção.
withTimeout
private fun timeoutDemo() {
launch {
txtOutput.text = ""
try {
withTimeout(1300L) {
repeat(10) { i ->
withContext(Dispatchers.Default) {
delay(500L)
}
addTextToTextView("I'm sleeping $i ...")
}
}
} catch (e: TimeoutCancellationException) { // opcional
addTextToTextView("Exception! ${e.message}")
}
}
}
withTimeoutOrNull
private fun timeoutOrNullDemo() {
launch {
txtOutput.text = ""
val task = async(Dispatchers.Default) {
delay(5000)
"Done!"
}
// suspend until task is finished or return null in 2 sec
val result = withTimeoutOrNull(2000) { task.await() }
addTextToTextView("Result: $result") // ui thread
}
}
Converting Callbacks to
Coroutines
class LocationManager {
fun getCurrentLocation(callback: (LatLng?) -> Unit) {
// get the location...
callback(LatLng(-8.187,-36.156))
}
}
suspend fun getMyLocation(lm: LocationManager): LatLng {
return suspendCoroutine { continuation ->
lm.getCurrentLocation { latLng ->
if (latLng == null) {
continuation.resumeWithException(
Exception("Fail to get user location")
)
} else {
continuation.resume(latLng)
}
}
}
}
Converting Callbacks to
Coroutines
class LocationManager {
fun getCurrentLocation(callback: (LatLng?) -> Unit) {
// get the location...
callback(LatLng(-8.187,-36.156))
}
}
suspend fun getMyLocation(lm: LocationManager): LatLng {
return suspendCancellableCoroutine { continuation ->
lm.getCurrentLocation { latLng ->
if (latLng == null) {
continuation.resumeWithException(
Exception("Fail to get user location")
)
} else {
continuation.resume(latLng)
}
}
}
}
Nos bastidores, uma suspending function é
convertida pelo compilador para uma função (de
mesmo nome) que recebe um objeto do tipo
Continuation.



fun sum(a: Int, b: Int, Continuation<Int>)
Continuation é uma interface que contém duas funções que
são invocadas para continuar com a execução da coroutine
(normalmente retornando um valor) ou levantar uma exceção
caso algum erro ocorra.

interface Continuation<in T> {
val context: CoroutineContext
fun resume(value: T)
fun resumeWithException(exception: Throwable)
}
Reactive Coroutines
Channel
• Serve basicamente para enviar dados de
uma coroutine para outra.

• O conceito de canal é similar a uma
blocking queue mas utiliza suspending
operations ao invés de blocking operations.
EXPERIMENTAL
2019-06-11 21:08:41.988 5545-5545/br.com.nglauber.coroutinesdemo I/System.out: 1
2019-06-11 21:08:41.990 5545-5545/br.com.nglauber.coroutinesdemo I/System.out: 4
2019-06-11 21:08:42.005 5545-5545/br.com.nglauber.coroutinesdemo I/System.out: 9
2019-06-11 21:08:42.005 5545-5545/br.com.nglauber.coroutinesdemo I/System.out: 16
2019-06-11 21:08:42.051 5545-5545/br.com.nglauber.coroutinesdemo I/System.out: 25
2019-06-11 21:08:42.051 5545-5545/br.com.nglauber.coroutinesdemo I/System.out: Done!
coroutineScope.launch {
val channel = Channel<Int>()
launch {
// this might be heavy CPU-consuming computation or
// async logic, we’ll just send five squares
for (x in 1..5) channel.send(x * x)
}
// here we print five received integers:
repeat(5) { println(channel.receive()) }
println("Done!")
}
import kotlinx.coroutines.channels.BroadcastChannel
import kotlinx.coroutines.channels.ReceiveChannel
class NumberSender {
private var currentValue = 0
private val numberChannel = BroadcastChannel<Int>(10)
fun getChannel(): ReceiveChannel<Int> =
numberChannel.openSubscription()
suspend fun sendNext() {
numberChannel.send(currentValue++)
}
fun close() = numberChannel.close()
}
class ChannelActivity : AppCompatActivity() {
private val sender = NumberSender()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_channel)
btnProduce.setOnClickListener {
lifecycleScope.launch {
sender.sendNext()
}
}
lifecycleScope.launch {
sender.getChannel().consumeEach {
txtOutput.append("Number: $it n")
}
}
}
override fun onDestroy() {
super.onDestroy()
sender.close()
}
}
Actors
• Basicamente, um ator é um elemento que
recebe mensagens por meio de um canal e
realiza algum trabalho baseado nelas.

• O retorno dessa função é um objeto do tipo
SendChannel que pode ser usado para
enviar mensagens para essa coroutine.
EXPERIMENTAL
class BooksWithActorViewModel : ViewModel() {
private var _screenState = MutableLiveData<State>()
val screenState: LiveData<State> = _screenState
private val actor: SendChannel<Action> = viewModelScope.actor {
for (action in this) when (action) {
is Action.LoadBooks -> doLoadBooks()
}
}
private suspend fun doLoadBooks() {
try {
_screenState.value = State.LoadingResults(true)
val books = withContext(Dispatchers.IO) {
BookHttp.loadBooks()
}
_screenState.value = State.BooksResult(books)
} catch (e: Exception) {
_screenState.value = State.ErrorResult(Exception(e))
} finally {
_screenState.value = State.LoadingResults(false)
}
}
fun loadBooksFromWeb() {
actor.offer(Action.LoadBooks)
}
override fun onCleared() {
super.onCleared()
actor.close()
}
}
class ActorDemoActivity : AppCompatActivity() {
private val viewModel: BooksWithActorViewModel by lazy { ... }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_actor_demo)
viewModel.screenState.observe(this, Observer { state ->
when (state) {
is State.LoadingResults -> showLoading(state.isLoading)
is State.BooksResult -> showResults(state.books)
is State.ErrorResult -> showError(state.t)
}
})
btnLoad.setOnClickListener {
viewModel.loadBooksFromWeb()
}
}
private fun showResults(books: List<Book>) {
txtResult.text = ""
books.forEach { txtResult.append("${it.title}n") }
}
private fun showLoading(show: Boolean) {
pbLoading.visibility = if (show) View.VISIBLE else View.GONE
}
private fun showError(t: Throwable) {
Toast.makeText(this, "${t.message}", Toast.LENGTH_SHORT).show()
}
}
Flow
• Flow é uma abstração de um cold stream.

• Nada é executado/emitido qualquer item até que algum
consumidor se registre no fluxo.

• Diversos operadores como no RxJava.
EXPERIMENTAL
@FlowPreview
public interface Flow<out T> {
public suspend fun collect(collector: FlowCollector<T>)
}
@FlowPreview
public interface FlowCollector<in T> {
public suspend fun emit(value: T)
}
private fun flowDemo() {
val intFlow = flow {
for (i in 0 until 10) {
emit(i) //calls emit directly from the body of a FlowCollector
}
}
launch {
txtOutput.text = ""
intFlow.collect { number ->
addTextToTextView("$numbern")
}
addTextToTextView("DONE!")
}
}
private fun flowDemo2() {
launch {
txtOutput.text = ""
(0..100).asFlow()
.map { it * it } // executed in IO
.filter { it % 4 == 0 } //executed in IO
.flowOn(Dispatchers.IO) //changes upstream context, asFlow, map and filter
.map { it * 2 } // not affected, continues in parent context
.flowOn(Dispatchers.Main)
.collect {number ->
addTextToTextView("$numbern")
}
}
}
import kotlinx.coroutines.channels.BroadcastChannel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
class NumberFlow {
private var currentValue = 0
private val numberChannel = BroadcastChannel<Int>(10)
fun getFlow(): Flow<Int> = numberChannel.asFlow()
suspend fun sendNext() {
numberChannel.send(currentValue++)
}
fun close() = numberChannel.close()
}
class FlowActivity : AppCompatActivity() {
private val sender = NumberFlow()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_flow)
btnProduce.setOnClickListener {
lifecycleScope.launch {
sender.sendNext()
}
}
lifecycleScope.launch {
sender.getFlow()
.collect {
txtOutput.append("Number: $it n")
}
}
}
override fun onDestroy() {
super.onDestroy()
sender.close()
}
}
Room
Room
dependencies {
def room_version = "2.1.0-rc01"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
// 👇 Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:$room_version"
...
}
@Dao
interface UserDao {
@Query("SELECT * FROM user")
suspend fun getAll(): List<User>
@Query("SELECT * FROM user WHERE uid = :id")
suspend fun getUser(id: Long): User
@Insert
suspend fun insert(users: User): Long
@Delete
suspend fun delete(user: User)
}
@Dao
interface UserDao {
@Query("SELECT * FROM user")
suspend fun getAll(): ReceiveChannel<List<User>>
@Query("SELECT * FROM user WHERE uid = :id")
suspend fun getUser(id: Long): ReceiveChannel<User>
@Insert
suspend fun insert(users: User): Long
@Delete
suspend fun delete(user: User)
}
NOT

IMPLEMENTED.

YET?
@Dao
interface UserDao {
@Query("SELECT * FROM user")
suspend fun getAll(): Flow<List<User>>
@Query("SELECT * FROM user WHERE uid = :id")
suspend fun getUser(id: Long): Flow<User>
@Insert
suspend fun insert(users: User): Long
@Delete
suspend fun delete(user: User)
}
NOT

IMPLEMENTED.

YET?
LiveData
LiveData
dependencies {
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01"
}
val users: LiveData<List<User>> = liveData {
val data = dao.getAll()
emit(data)
}
...
users.observe(this) { users ->
users.forEach { Log.d("NGVL", it.toString()) }
}
LiveData
@Dao
interface UserDao {
...
@Query("SELECT * FROM user")
fun getLiveAll(): LiveData<List<User>>
}
val users: LiveData<List<User>> = liveData {
val data = dao.getLiveAll()
emitSource(data)
}
...

users.observe(this) { users ->
users.forEach { Log.d("NGVL", it.toString()) }
}
Conclusão
• Coroutines vêm se tornando a forma de padrão para
realizar código assíncrono no Android.

• Essa é uma recomendação do Google.

• Além do Jetpack, outras bibliotecas estão migrando pro
Jetpack (ex: Retrofit).

• Muita atenção para as APIs experimentais de hoje. Elas
podem ser o seu código de amanhã!
Referências #1
• Android Suspenders (Android Dev Summit 2018)

https://www.youtube.com/watch?v=EOjq4OIWKqM

• Understand Kotlin Coroutines on Android (Google I/O 2019)

https://www.youtube.com/watch?v=BOHK_w09pVA

• Coroutines Guide

https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-
guide.md

• Android Suspenders by Chris Banes (KotlinConf 2018)

https://www.youtube.com/watch?v=P7ov_r1JZ1g

• Room & Coroutines (Florina Muntenescu)

https://medium.com/androiddevelopers/room-coroutines-422b786dc4c5
Referências #2
• Using Kotlin Coroutines in your Android App

https://codelabs.developers.google.com/codelabs/kotlin-coroutines

• Use Kotlin coroutines with Architecture Components

https://developer.android.com/topic/libraries/architecture/coroutines

• Create a Clean-Code App with Kotlin Coroutines and Android Architecture
Components

https://blog.elpassion.com/create-a-clean-code-app-with-kotlin-coroutines-
and-android-architecture-components-f533b04b5431

• Android Coroutine Recipes (Dmytro Danylyk)

https://proandroiddev.com/android-coroutine-recipes-33467a4302e9

• Kotlin Coroutines patterns & anti-patterns

https://proandroiddev.com/kotlin-coroutines-patterns-anti-patterns-
f9d12984c68e
Referências #3
• The reason to avoid GlobalScope (Roman Elizarov)

https://medium.com/@elizarov/the-reason-to-avoid-globalscope-835337445abc
• WorkManager meets Kotlin (Pietro Maggi)

https://medium.com/androiddevelopers/workmanager-meets-kotlin-
b9ad02f7405e

• Coroutine Context and Scope (Roman Elizarov)

https://medium.com/@elizarov/coroutine-context-and-scope-c8b255d59055

• Easy Coroutines in Android: viewModelScope (Manuel Vivo)

https://medium.com/androiddevelopers/easy-coroutines-in-android-
viewmodelscope-25bffb605471

• Exceed the Android Speed Limit

https://medium.com/androiddevelopers/exceed-the-android-speed-limit-
b73a0692abc1
Referências #4
• An Early look at Kotlin Coroutine’s Flow

https://proandroiddev.com/an-early-look-at-kotlin-coroutines-
flow-62e46baa6eb0

• Coroutines on Android (Sean McQuillan)

https://medium.com/androiddevelopers/coroutines-on-android-part-i-getting-
the-background-3e0e54d20bb
• Kotlin Flows and Coroutines (Roman Elizarov)

https://medium.com/@elizarov/kotlin-flows-and-coroutines-256260fb3bdb
• Simple design of Kotlin Flow (Roman Elizarov)

https://medium.com/@elizarov/simple-design-of-kotlin-flow-4725e7398c4c
• React Streams and Kotlin Flows (Roman Elizarov)

https://medium.com/@elizarov/reactive-streams-and-kotlin-flows-
bfd12772cda4
Obrigado!
@nglauber
www.nglauber.com.br

youtube.com/nglauber
slideshare.com/nglauber
Ad

More Related Content

What's hot (20)

Reactive, component 그리고 angular2
Reactive, component 그리고  angular2Reactive, component 그리고  angular2
Reactive, component 그리고 angular2
Jeado Ko
 
Writing native bindings to node.js in C++
Writing native bindings to node.js in C++Writing native bindings to node.js in C++
Writing native bindings to node.js in C++
nsm.nikhil
 
Cascadia.js: Don't Cross the Streams
Cascadia.js: Don't Cross the StreamsCascadia.js: Don't Cross the Streams
Cascadia.js: Don't Cross the Streams
mattpodwysocki
 
rx.js make async programming simpler
rx.js make async programming simplerrx.js make async programming simpler
rx.js make async programming simpler
Alexander Mostovenko
 
RDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по DipRDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по Dip
RAMBLER&Co
 
Snapshot clone-boot-presentation-final
Snapshot clone-boot-presentation-finalSnapshot clone-boot-presentation-final
Snapshot clone-boot-presentation-final
Open Stack
 
Ansible fest Presentation slides
Ansible fest Presentation slidesAnsible fest Presentation slides
Ansible fest Presentation slides
Aaron Carey
 
Lua: the world's most infuriating language
Lua: the world's most infuriating languageLua: the world's most infuriating language
Lua: the world's most infuriating language
jgrahamc
 
Playing With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.jsPlaying With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.js
Mike Hagedorn
 
Matthew Eernisse, NodeJs, .toster {webdev}
Matthew Eernisse, NodeJs, .toster {webdev}Matthew Eernisse, NodeJs, .toster {webdev}
Matthew Eernisse, NodeJs, .toster {webdev}
.toster
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016
Ben Lesh
 
Rethink Async With RXJS
Rethink Async With RXJSRethink Async With RXJS
Rethink Async With RXJS
Ryan Anklam
 
PuppetCamp SEA 1 - Version Control with Puppet
PuppetCamp SEA 1 - Version Control with PuppetPuppetCamp SEA 1 - Version Control with Puppet
PuppetCamp SEA 1 - Version Control with Puppet
Walter Heck
 
HAB Software Woes
HAB Software WoesHAB Software Woes
HAB Software Woes
jgrahamc
 
Async Frontiers
Async FrontiersAsync Frontiers
Async Frontiers
Domenic Denicola
 
rake puppetexpert:create - Puppet Camp Silicon Valley 2014
rake puppetexpert:create - Puppet Camp Silicon Valley 2014rake puppetexpert:create - Puppet Camp Silicon Valley 2014
rake puppetexpert:create - Puppet Camp Silicon Valley 2014
nvpuppet
 
Automating Kubernetes Environments with Ansible
Automating Kubernetes Environments with AnsibleAutomating Kubernetes Environments with Ansible
Automating Kubernetes Environments with Ansible
Timothy Appnel
 
Developing JavaScript Widgets
Developing JavaScript WidgetsDeveloping JavaScript Widgets
Developing JavaScript Widgets
Konstantin Käfer
 
303 TANSTAAFL: Using Open Source iPhone UI Code
303 TANSTAAFL: Using Open Source iPhone UI Code303 TANSTAAFL: Using Open Source iPhone UI Code
303 TANSTAAFL: Using Open Source iPhone UI Code
jonmarimba
 
Testing Backbone applications with Jasmine
Testing Backbone applications with JasmineTesting Backbone applications with Jasmine
Testing Backbone applications with Jasmine
Leon van der Grient
 
Reactive, component 그리고 angular2
Reactive, component 그리고  angular2Reactive, component 그리고  angular2
Reactive, component 그리고 angular2
Jeado Ko
 
Writing native bindings to node.js in C++
Writing native bindings to node.js in C++Writing native bindings to node.js in C++
Writing native bindings to node.js in C++
nsm.nikhil
 
Cascadia.js: Don't Cross the Streams
Cascadia.js: Don't Cross the StreamsCascadia.js: Don't Cross the Streams
Cascadia.js: Don't Cross the Streams
mattpodwysocki
 
rx.js make async programming simpler
rx.js make async programming simplerrx.js make async programming simpler
rx.js make async programming simpler
Alexander Mostovenko
 
RDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по DipRDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по Dip
RAMBLER&Co
 
Snapshot clone-boot-presentation-final
Snapshot clone-boot-presentation-finalSnapshot clone-boot-presentation-final
Snapshot clone-boot-presentation-final
Open Stack
 
Ansible fest Presentation slides
Ansible fest Presentation slidesAnsible fest Presentation slides
Ansible fest Presentation slides
Aaron Carey
 
Lua: the world's most infuriating language
Lua: the world's most infuriating languageLua: the world's most infuriating language
Lua: the world's most infuriating language
jgrahamc
 
Playing With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.jsPlaying With Fire - An Introduction to Node.js
Playing With Fire - An Introduction to Node.js
Mike Hagedorn
 
Matthew Eernisse, NodeJs, .toster {webdev}
Matthew Eernisse, NodeJs, .toster {webdev}Matthew Eernisse, NodeJs, .toster {webdev}
Matthew Eernisse, NodeJs, .toster {webdev}
.toster
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016
Ben Lesh
 
Rethink Async With RXJS
Rethink Async With RXJSRethink Async With RXJS
Rethink Async With RXJS
Ryan Anklam
 
PuppetCamp SEA 1 - Version Control with Puppet
PuppetCamp SEA 1 - Version Control with PuppetPuppetCamp SEA 1 - Version Control with Puppet
PuppetCamp SEA 1 - Version Control with Puppet
Walter Heck
 
HAB Software Woes
HAB Software WoesHAB Software Woes
HAB Software Woes
jgrahamc
 
rake puppetexpert:create - Puppet Camp Silicon Valley 2014
rake puppetexpert:create - Puppet Camp Silicon Valley 2014rake puppetexpert:create - Puppet Camp Silicon Valley 2014
rake puppetexpert:create - Puppet Camp Silicon Valley 2014
nvpuppet
 
Automating Kubernetes Environments with Ansible
Automating Kubernetes Environments with AnsibleAutomating Kubernetes Environments with Ansible
Automating Kubernetes Environments with Ansible
Timothy Appnel
 
Developing JavaScript Widgets
Developing JavaScript WidgetsDeveloping JavaScript Widgets
Developing JavaScript Widgets
Konstantin Käfer
 
303 TANSTAAFL: Using Open Source iPhone UI Code
303 TANSTAAFL: Using Open Source iPhone UI Code303 TANSTAAFL: Using Open Source iPhone UI Code
303 TANSTAAFL: Using Open Source iPhone UI Code
jonmarimba
 
Testing Backbone applications with Jasmine
Testing Backbone applications with JasmineTesting Backbone applications with Jasmine
Testing Backbone applications with Jasmine
Leon van der Grient
 

Similar to Aplicações assíncronas no Android com Coroutines & Jetpack (20)

Writing Maintainable JavaScript
Writing Maintainable JavaScriptWriting Maintainable JavaScript
Writing Maintainable JavaScript
Andrew Dupont
 
Emerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the HorizonEmerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the Horizon
Alex Payne
 
droidcon Transylvania - Kotlin Coroutines
droidcon Transylvania - Kotlin Coroutinesdroidcon Transylvania - Kotlin Coroutines
droidcon Transylvania - Kotlin Coroutines
Arthur Nagy
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
Sven Haiges
 
OpenStack Horizon: Controlling the Cloud using Django
OpenStack Horizon: Controlling the Cloud using DjangoOpenStack Horizon: Controlling the Cloud using Django
OpenStack Horizon: Controlling the Cloud using Django
David Lapsley
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
Konstantin Kudryashov
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
MongoDB
 
Functional programming using underscorejs
Functional programming using underscorejsFunctional programming using underscorejs
Functional programming using underscorejs
偉格 高
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
David Padbury
 
Swift - One step forward from Obj-C
Swift -  One step forward from Obj-CSwift -  One step forward from Obj-C
Swift - One step forward from Obj-C
Nissan Tsafrir
 
mobl
moblmobl
mobl
zefhemel
 
Async task, threads, pools, and executors oh my!
Async task, threads, pools, and executors oh my!Async task, threads, pools, and executors oh my!
Async task, threads, pools, and executors oh my!
Stacy Devino
 
Introduction to Protractor
Introduction to ProtractorIntroduction to Protractor
Introduction to Protractor
Jie-Wei Wu
 
CS101- Introduction to Computing- Lecture 35
CS101- Introduction to Computing- Lecture 35CS101- Introduction to Computing- Lecture 35
CS101- Introduction to Computing- Lecture 35
Bilal Ahmed
 
Cloud Orchestration with RightScale Cloud Workflow
Cloud Orchestration with RightScale Cloud WorkflowCloud Orchestration with RightScale Cloud Workflow
Cloud Orchestration with RightScale Cloud Workflow
RightScale
 
Kotlin - Coroutine
Kotlin - CoroutineKotlin - Coroutine
Kotlin - Coroutine
Sean Tsai
 
Kotlin from-scratch 3 - coroutines
Kotlin from-scratch 3 - coroutinesKotlin from-scratch 3 - coroutines
Kotlin from-scratch 3 - coroutines
Franco Lombardo
 
Kotlin coroutine - the next step for RxJava developer?
Kotlin coroutine - the next step for RxJava developer?Kotlin coroutine - the next step for RxJava developer?
Kotlin coroutine - the next step for RxJava developer?
Artur Latoszewski
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
Dongmin Yu
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
Nelson Glauber Leal
 
Writing Maintainable JavaScript
Writing Maintainable JavaScriptWriting Maintainable JavaScript
Writing Maintainable JavaScript
Andrew Dupont
 
Emerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the HorizonEmerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the Horizon
Alex Payne
 
droidcon Transylvania - Kotlin Coroutines
droidcon Transylvania - Kotlin Coroutinesdroidcon Transylvania - Kotlin Coroutines
droidcon Transylvania - Kotlin Coroutines
Arthur Nagy
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
Sven Haiges
 
OpenStack Horizon: Controlling the Cloud using Django
OpenStack Horizon: Controlling the Cloud using DjangoOpenStack Horizon: Controlling the Cloud using Django
OpenStack Horizon: Controlling the Cloud using Django
David Lapsley
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
Konstantin Kudryashov
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
MongoDB
 
Functional programming using underscorejs
Functional programming using underscorejsFunctional programming using underscorejs
Functional programming using underscorejs
偉格 高
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
David Padbury
 
Swift - One step forward from Obj-C
Swift -  One step forward from Obj-CSwift -  One step forward from Obj-C
Swift - One step forward from Obj-C
Nissan Tsafrir
 
Async task, threads, pools, and executors oh my!
Async task, threads, pools, and executors oh my!Async task, threads, pools, and executors oh my!
Async task, threads, pools, and executors oh my!
Stacy Devino
 
Introduction to Protractor
Introduction to ProtractorIntroduction to Protractor
Introduction to Protractor
Jie-Wei Wu
 
CS101- Introduction to Computing- Lecture 35
CS101- Introduction to Computing- Lecture 35CS101- Introduction to Computing- Lecture 35
CS101- Introduction to Computing- Lecture 35
Bilal Ahmed
 
Cloud Orchestration with RightScale Cloud Workflow
Cloud Orchestration with RightScale Cloud WorkflowCloud Orchestration with RightScale Cloud Workflow
Cloud Orchestration with RightScale Cloud Workflow
RightScale
 
Kotlin - Coroutine
Kotlin - CoroutineKotlin - Coroutine
Kotlin - Coroutine
Sean Tsai
 
Kotlin from-scratch 3 - coroutines
Kotlin from-scratch 3 - coroutinesKotlin from-scratch 3 - coroutines
Kotlin from-scratch 3 - coroutines
Franco Lombardo
 
Kotlin coroutine - the next step for RxJava developer?
Kotlin coroutine - the next step for RxJava developer?Kotlin coroutine - the next step for RxJava developer?
Kotlin coroutine - the next step for RxJava developer?
Artur Latoszewski
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
Dongmin Yu
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
Nelson Glauber Leal
 
Ad

More from Nelson Glauber Leal (20)

Insights no desenvolvimento Android para 2024
Insights no desenvolvimento Android para 2024Insights no desenvolvimento Android para 2024
Insights no desenvolvimento Android para 2024
Nelson Glauber Leal
 
Seu primeiro app Android e iOS com Compose Multiplatform
Seu primeiro app Android e iOS com Compose MultiplatformSeu primeiro app Android e iOS com Compose Multiplatform
Seu primeiro app Android e iOS com Compose Multiplatform
Nelson Glauber Leal
 
Desenvolvimento Moderno de Aplicações Android 2023
Desenvolvimento Moderno de Aplicações Android 2023Desenvolvimento Moderno de Aplicações Android 2023
Desenvolvimento Moderno de Aplicações Android 2023
Nelson Glauber Leal
 
Novidades incríveis do Android em 2023
Novidades incríveis do Android em 2023Novidades incríveis do Android em 2023
Novidades incríveis do Android em 2023
Nelson Glauber Leal
 
Novidades das Bibliotecas Jetpack do Android (2021)
Novidades das Bibliotecas Jetpack do Android (2021)Novidades das Bibliotecas Jetpack do Android (2021)
Novidades das Bibliotecas Jetpack do Android (2021)
Nelson Glauber Leal
 
Android Jetpack Compose - Turkey 2021
Android Jetpack Compose - Turkey 2021Android Jetpack Compose - Turkey 2021
Android Jetpack Compose - Turkey 2021
Nelson Glauber Leal
 
Jetpack Compose a new way to implement UI on Android
Jetpack Compose a new way to implement UI on AndroidJetpack Compose a new way to implement UI on Android
Jetpack Compose a new way to implement UI on Android
Nelson Glauber Leal
 
Jetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no AndroidJetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no Android
Nelson Glauber Leal
 
O que é preciso para ser um desenvolvedor Android
O que é preciso para ser um desenvolvedor AndroidO que é preciso para ser um desenvolvedor Android
O que é preciso para ser um desenvolvedor Android
Nelson Glauber Leal
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
Nelson Glauber Leal
 
Mastering Kotlin Standard Library
Mastering Kotlin Standard LibraryMastering Kotlin Standard Library
Mastering Kotlin Standard Library
Nelson Glauber Leal
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using Room
Nelson Glauber Leal
 
Arquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com JetpackArquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com Jetpack
Nelson Glauber Leal
 
Desenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos AndroidDesenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos Android
Nelson Glauber Leal
 
Desenvolvimento Moderno de aplicativos Android
Desenvolvimento Moderno de aplicativos AndroidDesenvolvimento Moderno de aplicativos Android
Desenvolvimento Moderno de aplicativos Android
Nelson Glauber Leal
 
Turbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com KotlinTurbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com Kotlin
Nelson Glauber Leal
 
Tudo que você precisa saber sobre Constraint Layout
Tudo que você precisa saber sobre Constraint LayoutTudo que você precisa saber sobre Constraint Layout
Tudo que você precisa saber sobre Constraint Layout
Nelson Glauber Leal
 
Persistência de Dados no SQLite com Room
Persistência de Dados no SQLite com RoomPersistência de Dados no SQLite com Room
Persistência de Dados no SQLite com Room
Nelson Glauber Leal
 
The world of Android Animations
The world of Android AnimationsThe world of Android Animations
The world of Android Animations
Nelson Glauber Leal
 
Android Constraint Layout
Android Constraint LayoutAndroid Constraint Layout
Android Constraint Layout
Nelson Glauber Leal
 
Insights no desenvolvimento Android para 2024
Insights no desenvolvimento Android para 2024Insights no desenvolvimento Android para 2024
Insights no desenvolvimento Android para 2024
Nelson Glauber Leal
 
Seu primeiro app Android e iOS com Compose Multiplatform
Seu primeiro app Android e iOS com Compose MultiplatformSeu primeiro app Android e iOS com Compose Multiplatform
Seu primeiro app Android e iOS com Compose Multiplatform
Nelson Glauber Leal
 
Desenvolvimento Moderno de Aplicações Android 2023
Desenvolvimento Moderno de Aplicações Android 2023Desenvolvimento Moderno de Aplicações Android 2023
Desenvolvimento Moderno de Aplicações Android 2023
Nelson Glauber Leal
 
Novidades incríveis do Android em 2023
Novidades incríveis do Android em 2023Novidades incríveis do Android em 2023
Novidades incríveis do Android em 2023
Nelson Glauber Leal
 
Novidades das Bibliotecas Jetpack do Android (2021)
Novidades das Bibliotecas Jetpack do Android (2021)Novidades das Bibliotecas Jetpack do Android (2021)
Novidades das Bibliotecas Jetpack do Android (2021)
Nelson Glauber Leal
 
Android Jetpack Compose - Turkey 2021
Android Jetpack Compose - Turkey 2021Android Jetpack Compose - Turkey 2021
Android Jetpack Compose - Turkey 2021
Nelson Glauber Leal
 
Jetpack Compose a new way to implement UI on Android
Jetpack Compose a new way to implement UI on AndroidJetpack Compose a new way to implement UI on Android
Jetpack Compose a new way to implement UI on Android
Nelson Glauber Leal
 
Jetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no AndroidJetpack Compose a nova forma de implementar UI no Android
Jetpack Compose a nova forma de implementar UI no Android
Nelson Glauber Leal
 
O que é preciso para ser um desenvolvedor Android
O que é preciso para ser um desenvolvedor AndroidO que é preciso para ser um desenvolvedor Android
O que é preciso para ser um desenvolvedor Android
Nelson Glauber Leal
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
Nelson Glauber Leal
 
Mastering Kotlin Standard Library
Mastering Kotlin Standard LibraryMastering Kotlin Standard Library
Mastering Kotlin Standard Library
Nelson Glauber Leal
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using Room
Nelson Glauber Leal
 
Arquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com JetpackArquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com Jetpack
Nelson Glauber Leal
 
Desenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos AndroidDesenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos Android
Nelson Glauber Leal
 
Desenvolvimento Moderno de aplicativos Android
Desenvolvimento Moderno de aplicativos AndroidDesenvolvimento Moderno de aplicativos Android
Desenvolvimento Moderno de aplicativos Android
Nelson Glauber Leal
 
Turbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com KotlinTurbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com Kotlin
Nelson Glauber Leal
 
Tudo que você precisa saber sobre Constraint Layout
Tudo que você precisa saber sobre Constraint LayoutTudo que você precisa saber sobre Constraint Layout
Tudo que você precisa saber sobre Constraint Layout
Nelson Glauber Leal
 
Persistência de Dados no SQLite com Room
Persistência de Dados no SQLite com RoomPersistência de Dados no SQLite com Room
Persistência de Dados no SQLite com Room
Nelson Glauber Leal
 
Ad

Recently uploaded (20)

Troubleshooting JVM Outages – 3 Fortune 500 case studies
Troubleshooting JVM Outages – 3 Fortune 500 case studiesTroubleshooting JVM Outages – 3 Fortune 500 case studies
Troubleshooting JVM Outages – 3 Fortune 500 case studies
Tier1 app
 
A Comprehensive Guide to CRM Software Benefits for Every Business Stage
A Comprehensive Guide to CRM Software Benefits for Every Business StageA Comprehensive Guide to CRM Software Benefits for Every Business Stage
A Comprehensive Guide to CRM Software Benefits for Every Business Stage
SynapseIndia
 
Let's Do Bad Things to Unsecured Containers
Let's Do Bad Things to Unsecured ContainersLet's Do Bad Things to Unsecured Containers
Let's Do Bad Things to Unsecured Containers
Gene Gotimer
 
Best HR and Payroll Software in Bangladesh - accordHRM
Best HR and Payroll Software in Bangladesh - accordHRMBest HR and Payroll Software in Bangladesh - accordHRM
Best HR and Payroll Software in Bangladesh - accordHRM
accordHRM
 
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptxThe-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
james brownuae
 
Lumion Pro Crack + 2025 Activation Key Free Code
Lumion Pro Crack + 2025 Activation Key Free CodeLumion Pro Crack + 2025 Activation Key Free Code
Lumion Pro Crack + 2025 Activation Key Free Code
raheemk1122g
 
How I solved production issues with OpenTelemetry
How I solved production issues with OpenTelemetryHow I solved production issues with OpenTelemetry
How I solved production issues with OpenTelemetry
Cees Bos
 
Welcome to QA Summit 2025.
Welcome to QA Summit 2025.Welcome to QA Summit 2025.
Welcome to QA Summit 2025.
QA Summit
 
Do not let staffing shortages and limited fiscal view hamper your cause
Do not let staffing shortages and limited fiscal view hamper your causeDo not let staffing shortages and limited fiscal view hamper your cause
Do not let staffing shortages and limited fiscal view hamper your cause
Fexle Services Pvt. Ltd.
 
Deploying & Testing Agentforce - End-to-end with Copado - Ewenb Clark
Deploying & Testing Agentforce - End-to-end with Copado - Ewenb ClarkDeploying & Testing Agentforce - End-to-end with Copado - Ewenb Clark
Deploying & Testing Agentforce - End-to-end with Copado - Ewenb Clark
Peter Caitens
 
How to Troubleshoot 9 Types of OutOfMemoryError
How to Troubleshoot 9 Types of OutOfMemoryErrorHow to Troubleshoot 9 Types of OutOfMemoryError
How to Troubleshoot 9 Types of OutOfMemoryError
Tier1 app
 
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by AjathMobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Ajath Infotech Technologies LLC
 
GC Tuning: A Masterpiece in Performance Engineering
GC Tuning: A Masterpiece in Performance EngineeringGC Tuning: A Masterpiece in Performance Engineering
GC Tuning: A Masterpiece in Performance Engineering
Tier1 app
 
NYC ACE 08-May-2025-Combined Presentation.pdf
NYC ACE 08-May-2025-Combined Presentation.pdfNYC ACE 08-May-2025-Combined Presentation.pdf
NYC ACE 08-May-2025-Combined Presentation.pdf
AUGNYC
 
UI/UX Design & Development and Servicess
UI/UX Design & Development and ServicessUI/UX Design & Development and Servicess
UI/UX Design & Development and Servicess
marketing810348
 
Quasar Framework Introduction for C++ develpoers
Quasar Framework Introduction for C++ develpoersQuasar Framework Introduction for C++ develpoers
Quasar Framework Introduction for C++ develpoers
sadadkhah
 
Passkeys and cbSecurity Led by Eric Peterson.pdf
Passkeys and cbSecurity Led by Eric Peterson.pdfPasskeys and cbSecurity Led by Eric Peterson.pdf
Passkeys and cbSecurity Led by Eric Peterson.pdf
Ortus Solutions, Corp
 
Exchange Migration Tool- Shoviv Software
Exchange Migration Tool- Shoviv SoftwareExchange Migration Tool- Shoviv Software
Exchange Migration Tool- Shoviv Software
Shoviv Software
 
Reinventing Microservices Efficiency and Innovation with Single-Runtime
Reinventing Microservices Efficiency and Innovation with Single-RuntimeReinventing Microservices Efficiency and Innovation with Single-Runtime
Reinventing Microservices Efficiency and Innovation with Single-Runtime
Natan Silnitsky
 
iTop VPN With Crack Lifetime Activation Key
iTop VPN With Crack Lifetime Activation KeyiTop VPN With Crack Lifetime Activation Key
iTop VPN With Crack Lifetime Activation Key
raheemk1122g
 
Troubleshooting JVM Outages – 3 Fortune 500 case studies
Troubleshooting JVM Outages – 3 Fortune 500 case studiesTroubleshooting JVM Outages – 3 Fortune 500 case studies
Troubleshooting JVM Outages – 3 Fortune 500 case studies
Tier1 app
 
A Comprehensive Guide to CRM Software Benefits for Every Business Stage
A Comprehensive Guide to CRM Software Benefits for Every Business StageA Comprehensive Guide to CRM Software Benefits for Every Business Stage
A Comprehensive Guide to CRM Software Benefits for Every Business Stage
SynapseIndia
 
Let's Do Bad Things to Unsecured Containers
Let's Do Bad Things to Unsecured ContainersLet's Do Bad Things to Unsecured Containers
Let's Do Bad Things to Unsecured Containers
Gene Gotimer
 
Best HR and Payroll Software in Bangladesh - accordHRM
Best HR and Payroll Software in Bangladesh - accordHRMBest HR and Payroll Software in Bangladesh - accordHRM
Best HR and Payroll Software in Bangladesh - accordHRM
accordHRM
 
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptxThe-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
james brownuae
 
Lumion Pro Crack + 2025 Activation Key Free Code
Lumion Pro Crack + 2025 Activation Key Free CodeLumion Pro Crack + 2025 Activation Key Free Code
Lumion Pro Crack + 2025 Activation Key Free Code
raheemk1122g
 
How I solved production issues with OpenTelemetry
How I solved production issues with OpenTelemetryHow I solved production issues with OpenTelemetry
How I solved production issues with OpenTelemetry
Cees Bos
 
Welcome to QA Summit 2025.
Welcome to QA Summit 2025.Welcome to QA Summit 2025.
Welcome to QA Summit 2025.
QA Summit
 
Do not let staffing shortages and limited fiscal view hamper your cause
Do not let staffing shortages and limited fiscal view hamper your causeDo not let staffing shortages and limited fiscal view hamper your cause
Do not let staffing shortages and limited fiscal view hamper your cause
Fexle Services Pvt. Ltd.
 
Deploying & Testing Agentforce - End-to-end with Copado - Ewenb Clark
Deploying & Testing Agentforce - End-to-end with Copado - Ewenb ClarkDeploying & Testing Agentforce - End-to-end with Copado - Ewenb Clark
Deploying & Testing Agentforce - End-to-end with Copado - Ewenb Clark
Peter Caitens
 
How to Troubleshoot 9 Types of OutOfMemoryError
How to Troubleshoot 9 Types of OutOfMemoryErrorHow to Troubleshoot 9 Types of OutOfMemoryError
How to Troubleshoot 9 Types of OutOfMemoryError
Tier1 app
 
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by AjathMobile Application Developer Dubai | Custom App Solutions by Ajath
Mobile Application Developer Dubai | Custom App Solutions by Ajath
Ajath Infotech Technologies LLC
 
GC Tuning: A Masterpiece in Performance Engineering
GC Tuning: A Masterpiece in Performance EngineeringGC Tuning: A Masterpiece in Performance Engineering
GC Tuning: A Masterpiece in Performance Engineering
Tier1 app
 
NYC ACE 08-May-2025-Combined Presentation.pdf
NYC ACE 08-May-2025-Combined Presentation.pdfNYC ACE 08-May-2025-Combined Presentation.pdf
NYC ACE 08-May-2025-Combined Presentation.pdf
AUGNYC
 
UI/UX Design & Development and Servicess
UI/UX Design & Development and ServicessUI/UX Design & Development and Servicess
UI/UX Design & Development and Servicess
marketing810348
 
Quasar Framework Introduction for C++ develpoers
Quasar Framework Introduction for C++ develpoersQuasar Framework Introduction for C++ develpoers
Quasar Framework Introduction for C++ develpoers
sadadkhah
 
Passkeys and cbSecurity Led by Eric Peterson.pdf
Passkeys and cbSecurity Led by Eric Peterson.pdfPasskeys and cbSecurity Led by Eric Peterson.pdf
Passkeys and cbSecurity Led by Eric Peterson.pdf
Ortus Solutions, Corp
 
Exchange Migration Tool- Shoviv Software
Exchange Migration Tool- Shoviv SoftwareExchange Migration Tool- Shoviv Software
Exchange Migration Tool- Shoviv Software
Shoviv Software
 
Reinventing Microservices Efficiency and Innovation with Single-Runtime
Reinventing Microservices Efficiency and Innovation with Single-RuntimeReinventing Microservices Efficiency and Innovation with Single-Runtime
Reinventing Microservices Efficiency and Innovation with Single-Runtime
Natan Silnitsky
 
iTop VPN With Crack Lifetime Activation Key
iTop VPN With Crack Lifetime Activation KeyiTop VPN With Crack Lifetime Activation Key
iTop VPN With Crack Lifetime Activation Key
raheemk1122g
 

Aplicações assíncronas no Android com Coroutines & Jetpack

  • 1. Coroutines & Jetpack Aplicações assíncronas no Android com Nelson Glauber @nglauber
 slideshare.com/nglauber
 youtube.com/nglauber
  • 2. A main thread do Android • Carregar arquivo de layout • Desenhar as views • Tratar os eventos de UI • …
  • 3. A main thread do Android
  • 4. A main thread do Android
  • 6. Async no Android • AsyncTask ! • Thread + Handler " • Loaders (deprecated) ! • Volley #$ • RxJava 🧐
  • 7. Coroutines • Essencialmente, coroutines são light-weight threads. • Fácil de usar (sem mais "callbacks hell” e/ou centenas de operadores). • Úteis para operações de I/O ou qualquer outra tarefa computacional mais onerosa. • Permite a substituição de callbacks por operações assíncronas.
  • 8. Dependências dependencies { def coroutines_version = '1.2.1' implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version" ... }
  • 9. suspend • Suspending functions são o centro de tudo em Coroutines. Elas são basicamente funções que podem ser pausadas e retomadas após algum tempo. • Podem executar longas tarefas e aguardar o resultado sem bloquear a thread atual. • A sintaxe é idêntica a uma função “normal”, exceto pela adição da palavra reservada suspend. • Por si só, uma suspending function não é assíncrona. • Só pode ser chamada a partir de outra suspending function.
  • 10. import kotlinx.coroutines.runBlocking import org.junit.Test import org.junit.Assert.assertEquals class CalculatorUnitTest { @Test fun sum_isCorrect() = runBlocking { val calc = Calculator() assertEquals(4, calc.sum(2, 2)) } } import kotlinx.coroutines.delay class Calculator { suspend fun sum(a: Int, b: Int): Int { delay(5_000) return a + b } }
  • 11. Coroutines no Android • Para entendermos melhor as Coroutines no Android precisamos falar de 4 conceitos: • Job • Context • Scope • Dispatcher
  • 12. class MainActivity : AppCompatActivity() { private val job = Job() private val coroutineScope = CoroutineScope(job + Dispatchers.Main) override fun onDestroy() { super.onDestroy() job.cancel() } fun callWebService() { coroutineScope.launch { txtOutput.text = "" val books = withContext(Dispatchers.IO) { BookHttp.loadBooks() } books?.forEach { txtOutput.append("${it.title}n") } } } ...
  • 13. class MainActivity : AppCompatActivity() { private val job = Job() private val coroutineScope = CoroutineScope(job + Dispatchers.Main) override fun onDestroy() { super.onDestroy() job.cancel() } fun callWebService() { coroutineScope.launch { txtOutput.text = "" val books = withContext(Dispatchers.IO) { BookHttp.loadBooks() } books?.forEach { txtOutput.append("${it.title}n") } } } ... Job • Um Job representa uma tarefa ou conjunto de tarefas em background. • A função launch retorna um Job. • Mantém a referência do código que está em execução. • Pode possuir “filhos”. • Pode ser cancelado usando a função cancel.
  • 14. class MainActivity : AppCompatActivity() { private val job = Job() private val coroutineScope = CoroutineScope(job + Dispatchers.Main) override fun onDestroy() { super.onDestroy() job.cancel() } fun callWebService() { coroutineScope.launch { txtOutput.text = "" val books = withContext(Dispatchers.IO) { BookHttp.loadBooks() } books?.forEach { txtOutput.append("${it.title}n") } } } ... Context • É um conjunto de atributos que configuram uma coroutine. • Representada pela interface CoroutineContext. • Pode definir a política de threading, tratamento de exceções, etc.
  • 15. class MainActivity : AppCompatActivity() { private val job = Job() private val coroutineScope = CoroutineScope(job + Dispatchers.Main) override fun onDestroy() { super.onDestroy() job.cancel() } fun callWebService() { coroutineScope.launch { txtOutput.text = "" val books = withContext(Dispatchers.IO) { BookHttp.loadBooks() } books?.forEach { txtOutput.append("${it.title}n") } } } ... Scope • Um escopo serve como uma espécie de ciclo de vida para um conjunto de coroutines. • Coroutines sempre rodam em um escopo. • Permite um maior controle das tarefas em execução
  • 16. GlobalScope • O GlobalScope, como o nome sugere, é utilizado em tarefas cujo o escopo é global da aplicação. • O GlobalScope é considerado um anti-pattern no Android e deve ser evitado. private suspend fun loadName(): String { delay(5000) return "Glauber" } private fun firstCoroutine() { GlobalScope.launch { val name = loadName() println("$name!") } println("Hello, ") }
  • 17. class MainActivity : AppCompatActivity() { private val job = Job() private val coroutineScope = CoroutineScope(job + Dispatchers.Main) override fun onDestroy() { super.onDestroy() job.cancel() } fun callWebService() { coroutineScope.launch { txtOutput.text = "" val books = withContext(Dispatchers.IO) { BookHttp.loadBooks() } books?.forEach { txtOutput.append("${it.title}n") } } } ... Dispatcher • Um dispatcher define o pool de threads que a coroutine executará. • Default - É otimizado para processos que usam a CPU mais intensamente. • IO - recomendado para tarefas de rede ou arquivos. O pool de threads é compartilhado com o dispatcher DEFAULT. • Main - main thread do Android.
  • 18. fun callWebService() { coroutineScope.launch { txtOutput.text = "" val books = withContext(Dispatchers.IO) { BookHttp.loadBooks() } books?.forEach { addTextToTextView("${it.title}n") } } } &
  • 19. fun callWebService() { coroutineScope.launch { txtOutput.text = "" val books = BookHttp.loadBooks() books?.forEach { txtOutput.append("${it.title}n") } } } android.os.NetworkOnMainThreadException at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1513) at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:117) at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:105) at java.net.InetAddress.getAllByName(InetAddress.java:1154) at com.android.okhttp.Dns$1.lookup(Dns.java:39)
  • 20. FATAL EXCEPTION: DefaultDispatcher-worker-1 Process: br.com.nglauber.coroutinesdemo, PID: 26507 android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7753) at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1225) fun callWebService() { coroutineScope.launch(Dispatchers.IO){ txtOutput.text = "" val books = BookHttp.loadBooks() books?.forEach { txtOutput.append("${it.title}n") } } }
  • 21. class MainActivity : AppCompatActivity() { private val job = Job() private val coroutineScope = CoroutineScope(job + Dispatchers.Main) override fun onDestroy() { super.onDestroy() job.cancel() } fun callWebService() { coroutineScope.launch { txtOutput.text = "" val books = withContext(Dispatchers.IO) { BookHttp.loadBooks() } books?.forEach { txtOutput.append("${it.title}n") } } } ...
  • 22. class MainActivity : AppCompatActivity(), CoroutineScope { private val job = Job() override val coroutineContext: CoroutineContext get() = Dispatchers.Main + job override fun onDestroy() { super.onDestroy() job.cancel() } fun callWebService() { launch { txtOutput.text = "" val books = withContext(Dispatchers.IO) { BookHttp.loadBooks() } books?.forEach { txtOutput.append("${it.title}n") } } } ...
  • 24. Lifecycle Scope • Escopo atrelado ao ciclo de vida da Activity, Fragment ou View do Fragment • Além da função launch, podemos usar o launchWhenCreated, launchWhenStarted e launchWhenResumed. dependencies { ... implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha01" }
  • 25. class MyActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ... lifecycleScope.launch { ... } // or... lifecycleScope.launchWhenCreated { ... } // or... lifecycleScope.launchWhenStarted { ... } }
  • 26. class MyFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ... lifecycleScope.launch { ... } // or... lifecycleScope.launchWhenCreated { ... } // or... lifecycleScope.launchWhenStarted { ... } }
  • 27. class MyFragment: Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { viewLifecycleOwner.lifecycleScope.launch { ... } } }
  • 29. ViewModel Scope 
 
 Um ViewModel agora possui a propriedade viewModelScope. dependencies { implementation "androidx.lifecycle:lifecycle-extensions:2.2.0-alpha01" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-alpha01" testImplementation "androidx.arch.core:core-testing:2.1.0-beta01" }
  • 30. class MainViewModel : ViewModel() { private val _message = MutableLiveData<String>() val message: LiveData<String> = _message fun loadMessage() { viewModelScope.launch { val message = withContext(Dispatchers.IO) { loadMessageFromNetwork() } _message.value = message } } private suspend fun loadMessageFromNetwork() : String { delay(2_000) return "Hello from ViewModel" } }
  • 31. class MainActivity : AppCompatActivity() { private val viewModel: MainViewModel by lazy { ViewModelProviders.of(this).get(MainViewModel::class.java) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) ... viewModel.message.observe(this, Observer { s -> txtOutput.text = s }) viewModel.loadMessage() } ...
  • 33. WorkManager dependencies { def work_version = "2.1.0-beta02" implementation "androidx.work:work-runtime-ktx:$work_version" androidTestImplementation "androidx.work:work-testing:$work_version" }
  • 34. class MyWork(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) { override suspend fun doWork(): Result = try { val output = inputData.run { val x = getInt("x", 0) val y = getInt("y", 0) val result = Calculator().sum(x, y) workDataOf("result" to result) } Result.success(output) } catch (error: Throwable) { Result.failure() } } private fun callMyWork() { val request = OneTimeWorkRequestBuilder<MyWork>() .setInputData(workDataOf("x" to 84, "y" to 12)) .build() WorkManager.getInstance(this).run { enqueue(request) getWorkInfoByIdLiveData(request.id) .observe(this@MainActivity, Observer { if (it.state == WorkInfo.State.SUCCEEDED) { val result = it.outputData.getInt("result", 0) addTextToTextView("Result-> $result") } }) }
  • 36. Iniciando uma coroutine • As duas formas de iniciar uma coroutine são: • A função launch é uma “fire and forget”  que significa que não retornará o resultado para que a chamou (mas retornará um Job). • A função async retorna um objeto Deferred que permite obter o seu resultado.
  • 37. launch = Sequencial private fun sequentialCalls() { txtOutput.text = "" launch { val time = measureTimeMillis { val one = doSomethingUsefulOne() val two = doSomethingUsefulTwo() addTextToTextView("The answer is ${one + two}") } addTextToTextView("Completed in $time ms") } } The answer is 42
 Completed in 2030 ms
  • 38. async = Paralelo private fun parallelCalls() { txtOutput.text = "" launch { val time = measureTimeMillis { val one = async { doSomethingUsefulOne() } val two = async { doSomethingUsefulTwo() } addTextToTextView("The answer is ${one.await() + two.await()} ") } addTextToTextView("Completed in $time ms") } } The answer is 42
 Completed in 1038 ms
  • 39. Launch x Async Em quase todos os casos, deve-se usar a função launch para iniciar uma coroutine a partir de uma função “normal”. Uma função comum não pode chamar o await (porque ela é uma suspending function), então não faz muito sentido usar o async como ponto de partida.
  • 40. Exceptions • As exceções tem comportamentos diferentes para o launch e o async. 
  • 41. Exceptions - launch private fun handlingException() { launch { txtOutput.text = "" try { val a = methodThatThrowsException() addTextToTextView("Ok ${a}") } catch (e: Exception) { addTextToTextView("handlingException caught: ${e.message}") } } }
  • 42. Exceptions - async private fun handlingAsyncException() { launch { txtOutput.text = "" try { val task = async { throwingException() } addTextToTextView("Ok ${task.await()}") } catch (e: Exception) { addTextToTextView("handlingAsyncException caught: ${e}") } } }
  • 43. Exceptions - async #1 private fun handlingAsyncException1() { launch { txtOutput.text = "" val task = async(SupervisorJob(job)) { methodThatThrowsException() } try { addTextToTextView("Ok ${task.await()}") } catch (e: Throwable) { addTextToTextView("Erro! ${e.message}") } } }
  • 44. Exceptions - async #2 private fun handlingAsyncException2() { launch { txtOutput.text = "" supervisorScope { val task = async { methodThatThrowsException() } try { addTextToTextView("Ok ${task.await()}") } catch (e: Throwable) { addTextToTextView("Erro! ${e.message}") } } } }
  • 45. Exceptions - async #3 private fun handlingAsyncException3() { launch { txtOutput.text = "" try { coroutineScope { val task = async { methodThatThrowsException() } addTextToTextView("Ok ${task.await()}") } } catch (e: Throwable) { addTextToTextView("Erro! ${e.message}") } } }
  • 46. Cancelamento • Para cancelar um job, basta chamar o método cancel. • Uma vez cancelado o job não pode ser reusado. • Para cancelar os jobs filhos, use cancelChildren. • A propriedade isActive indica que o job está em execução, isCancelled cancelado, e isCompleted terminou sua execução. • Se cancelado enquanto suspenso, levanta CancellationException.
  • 47. private fun cancelDemo() { val startTime = System.currentTimeMillis() longJob = launch(Dispatchers.Default) { var nextPrintTime = startTime var i = 0 while (i < 20 && isActive) { // this == CoroutineScope, que possui isActive if (System.currentTimeMillis() >= nextPrintTime) { Log.d("NGVL","job: I'm sleeping ${i++} ...") nextPrintTime += 500L } } } }
  • 48. private fun nonCancellableJob() { nonCancellableJob = launch { withContext(NonCancellable) { println("job: I'm here") delay(5000L) println("job: I'm non-cancellable") } } }
  • 49. withTimeout • Executa uma coroutine levantando uma TimeoutCancellationException caso sua duração exceda o timeout especificado. • Uma vez que o cancelamento é apenas uma exceção, é possível trata-la facilmente. • É possível usar a função withTimeoutOrNull que é similar a withTimeout, mas retorna null ao invés de levantar a exceção.
  • 50. withTimeout private fun timeoutDemo() { launch { txtOutput.text = "" try { withTimeout(1300L) { repeat(10) { i -> withContext(Dispatchers.Default) { delay(500L) } addTextToTextView("I'm sleeping $i ...") } } } catch (e: TimeoutCancellationException) { // opcional addTextToTextView("Exception! ${e.message}") } } }
  • 51. withTimeoutOrNull private fun timeoutOrNullDemo() { launch { txtOutput.text = "" val task = async(Dispatchers.Default) { delay(5000) "Done!" } // suspend until task is finished or return null in 2 sec val result = withTimeoutOrNull(2000) { task.await() } addTextToTextView("Result: $result") // ui thread } }
  • 52. Converting Callbacks to Coroutines class LocationManager { fun getCurrentLocation(callback: (LatLng?) -> Unit) { // get the location... callback(LatLng(-8.187,-36.156)) } } suspend fun getMyLocation(lm: LocationManager): LatLng { return suspendCoroutine { continuation -> lm.getCurrentLocation { latLng -> if (latLng == null) { continuation.resumeWithException( Exception("Fail to get user location") ) } else { continuation.resume(latLng) } } } }
  • 53. Converting Callbacks to Coroutines class LocationManager { fun getCurrentLocation(callback: (LatLng?) -> Unit) { // get the location... callback(LatLng(-8.187,-36.156)) } } suspend fun getMyLocation(lm: LocationManager): LatLng { return suspendCancellableCoroutine { continuation -> lm.getCurrentLocation { latLng -> if (latLng == null) { continuation.resumeWithException( Exception("Fail to get user location") ) } else { continuation.resume(latLng) } } } }
  • 54. Nos bastidores, uma suspending function é convertida pelo compilador para uma função (de mesmo nome) que recebe um objeto do tipo Continuation.
 
 fun sum(a: Int, b: Int, Continuation<Int>) Continuation é uma interface que contém duas funções que são invocadas para continuar com a execução da coroutine (normalmente retornando um valor) ou levantar uma exceção caso algum erro ocorra.
 interface Continuation<in T> { val context: CoroutineContext fun resume(value: T) fun resumeWithException(exception: Throwable) }
  • 56. Channel • Serve basicamente para enviar dados de uma coroutine para outra. • O conceito de canal é similar a uma blocking queue mas utiliza suspending operations ao invés de blocking operations. EXPERIMENTAL
  • 57. 2019-06-11 21:08:41.988 5545-5545/br.com.nglauber.coroutinesdemo I/System.out: 1 2019-06-11 21:08:41.990 5545-5545/br.com.nglauber.coroutinesdemo I/System.out: 4 2019-06-11 21:08:42.005 5545-5545/br.com.nglauber.coroutinesdemo I/System.out: 9 2019-06-11 21:08:42.005 5545-5545/br.com.nglauber.coroutinesdemo I/System.out: 16 2019-06-11 21:08:42.051 5545-5545/br.com.nglauber.coroutinesdemo I/System.out: 25 2019-06-11 21:08:42.051 5545-5545/br.com.nglauber.coroutinesdemo I/System.out: Done! coroutineScope.launch { val channel = Channel<Int>() launch { // this might be heavy CPU-consuming computation or // async logic, we’ll just send five squares for (x in 1..5) channel.send(x * x) } // here we print five received integers: repeat(5) { println(channel.receive()) } println("Done!") }
  • 58. import kotlinx.coroutines.channels.BroadcastChannel import kotlinx.coroutines.channels.ReceiveChannel class NumberSender { private var currentValue = 0 private val numberChannel = BroadcastChannel<Int>(10) fun getChannel(): ReceiveChannel<Int> = numberChannel.openSubscription() suspend fun sendNext() { numberChannel.send(currentValue++) } fun close() = numberChannel.close() }
  • 59. class ChannelActivity : AppCompatActivity() { private val sender = NumberSender() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_channel) btnProduce.setOnClickListener { lifecycleScope.launch { sender.sendNext() } } lifecycleScope.launch { sender.getChannel().consumeEach { txtOutput.append("Number: $it n") } } } override fun onDestroy() { super.onDestroy() sender.close() } }
  • 60. Actors • Basicamente, um ator é um elemento que recebe mensagens por meio de um canal e realiza algum trabalho baseado nelas. • O retorno dessa função é um objeto do tipo SendChannel que pode ser usado para enviar mensagens para essa coroutine. EXPERIMENTAL
  • 61. class BooksWithActorViewModel : ViewModel() { private var _screenState = MutableLiveData<State>() val screenState: LiveData<State> = _screenState private val actor: SendChannel<Action> = viewModelScope.actor { for (action in this) when (action) { is Action.LoadBooks -> doLoadBooks() } } private suspend fun doLoadBooks() { try { _screenState.value = State.LoadingResults(true) val books = withContext(Dispatchers.IO) { BookHttp.loadBooks() } _screenState.value = State.BooksResult(books) } catch (e: Exception) { _screenState.value = State.ErrorResult(Exception(e)) } finally { _screenState.value = State.LoadingResults(false) } } fun loadBooksFromWeb() { actor.offer(Action.LoadBooks) } override fun onCleared() { super.onCleared() actor.close() } }
  • 62. class ActorDemoActivity : AppCompatActivity() { private val viewModel: BooksWithActorViewModel by lazy { ... } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_actor_demo) viewModel.screenState.observe(this, Observer { state -> when (state) { is State.LoadingResults -> showLoading(state.isLoading) is State.BooksResult -> showResults(state.books) is State.ErrorResult -> showError(state.t) } }) btnLoad.setOnClickListener { viewModel.loadBooksFromWeb() } } private fun showResults(books: List<Book>) { txtResult.text = "" books.forEach { txtResult.append("${it.title}n") } } private fun showLoading(show: Boolean) { pbLoading.visibility = if (show) View.VISIBLE else View.GONE } private fun showError(t: Throwable) { Toast.makeText(this, "${t.message}", Toast.LENGTH_SHORT).show() } }
  • 63. Flow • Flow é uma abstração de um cold stream. • Nada é executado/emitido qualquer item até que algum consumidor se registre no fluxo. • Diversos operadores como no RxJava. EXPERIMENTAL
  • 64. @FlowPreview public interface Flow<out T> { public suspend fun collect(collector: FlowCollector<T>) } @FlowPreview public interface FlowCollector<in T> { public suspend fun emit(value: T) }
  • 65. private fun flowDemo() { val intFlow = flow { for (i in 0 until 10) { emit(i) //calls emit directly from the body of a FlowCollector } } launch { txtOutput.text = "" intFlow.collect { number -> addTextToTextView("$numbern") } addTextToTextView("DONE!") } }
  • 66. private fun flowDemo2() { launch { txtOutput.text = "" (0..100).asFlow() .map { it * it } // executed in IO .filter { it % 4 == 0 } //executed in IO .flowOn(Dispatchers.IO) //changes upstream context, asFlow, map and filter .map { it * 2 } // not affected, continues in parent context .flowOn(Dispatchers.Main) .collect {number -> addTextToTextView("$numbern") } } }
  • 67. import kotlinx.coroutines.channels.BroadcastChannel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.asFlow class NumberFlow { private var currentValue = 0 private val numberChannel = BroadcastChannel<Int>(10) fun getFlow(): Flow<Int> = numberChannel.asFlow() suspend fun sendNext() { numberChannel.send(currentValue++) } fun close() = numberChannel.close() }
  • 68. class FlowActivity : AppCompatActivity() { private val sender = NumberFlow() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_flow) btnProduce.setOnClickListener { lifecycleScope.launch { sender.sendNext() } } lifecycleScope.launch { sender.getFlow() .collect { txtOutput.append("Number: $it n") } } } override fun onDestroy() { super.onDestroy() sender.close() } }
  • 69. Room
  • 70. Room dependencies { def room_version = "2.1.0-rc01" implementation "androidx.room:room-runtime:$room_version" kapt "androidx.room:room-compiler:$room_version" // 👇 Kotlin Extensions and Coroutines support for Room implementation "androidx.room:room-ktx:$room_version" ... }
  • 71. @Dao interface UserDao { @Query("SELECT * FROM user") suspend fun getAll(): List<User> @Query("SELECT * FROM user WHERE uid = :id") suspend fun getUser(id: Long): User @Insert suspend fun insert(users: User): Long @Delete suspend fun delete(user: User) }
  • 72. @Dao interface UserDao { @Query("SELECT * FROM user") suspend fun getAll(): ReceiveChannel<List<User>> @Query("SELECT * FROM user WHERE uid = :id") suspend fun getUser(id: Long): ReceiveChannel<User> @Insert suspend fun insert(users: User): Long @Delete suspend fun delete(user: User) } NOT
 IMPLEMENTED.
 YET?
  • 73. @Dao interface UserDao { @Query("SELECT * FROM user") suspend fun getAll(): Flow<List<User>> @Query("SELECT * FROM user WHERE uid = :id") suspend fun getUser(id: Long): Flow<User> @Insert suspend fun insert(users: User): Long @Delete suspend fun delete(user: User) } NOT
 IMPLEMENTED.
 YET?
  • 75. LiveData dependencies { implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01" } val users: LiveData<List<User>> = liveData { val data = dao.getAll() emit(data) } ... users.observe(this) { users -> users.forEach { Log.d("NGVL", it.toString()) } }
  • 76. LiveData @Dao interface UserDao { ... @Query("SELECT * FROM user") fun getLiveAll(): LiveData<List<User>> } val users: LiveData<List<User>> = liveData { val data = dao.getLiveAll() emitSource(data) } ...
 users.observe(this) { users -> users.forEach { Log.d("NGVL", it.toString()) } }
  • 77. Conclusão • Coroutines vêm se tornando a forma de padrão para realizar código assíncrono no Android. • Essa é uma recomendação do Google. • Além do Jetpack, outras bibliotecas estão migrando pro Jetpack (ex: Retrofit). • Muita atenção para as APIs experimentais de hoje. Elas podem ser o seu código de amanhã!
  • 78. Referências #1 • Android Suspenders (Android Dev Summit 2018)
 https://www.youtube.com/watch?v=EOjq4OIWKqM • Understand Kotlin Coroutines on Android (Google I/O 2019)
 https://www.youtube.com/watch?v=BOHK_w09pVA • Coroutines Guide
 https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines- guide.md • Android Suspenders by Chris Banes (KotlinConf 2018)
 https://www.youtube.com/watch?v=P7ov_r1JZ1g • Room & Coroutines (Florina Muntenescu)
 https://medium.com/androiddevelopers/room-coroutines-422b786dc4c5
  • 79. Referências #2 • Using Kotlin Coroutines in your Android App
 https://codelabs.developers.google.com/codelabs/kotlin-coroutines • Use Kotlin coroutines with Architecture Components
 https://developer.android.com/topic/libraries/architecture/coroutines • Create a Clean-Code App with Kotlin Coroutines and Android Architecture Components
 https://blog.elpassion.com/create-a-clean-code-app-with-kotlin-coroutines- and-android-architecture-components-f533b04b5431 • Android Coroutine Recipes (Dmytro Danylyk)
 https://proandroiddev.com/android-coroutine-recipes-33467a4302e9 • Kotlin Coroutines patterns & anti-patterns
 https://proandroiddev.com/kotlin-coroutines-patterns-anti-patterns- f9d12984c68e
  • 80. Referências #3 • The reason to avoid GlobalScope (Roman Elizarov)
 https://medium.com/@elizarov/the-reason-to-avoid-globalscope-835337445abc • WorkManager meets Kotlin (Pietro Maggi)
 https://medium.com/androiddevelopers/workmanager-meets-kotlin- b9ad02f7405e • Coroutine Context and Scope (Roman Elizarov)
 https://medium.com/@elizarov/coroutine-context-and-scope-c8b255d59055 • Easy Coroutines in Android: viewModelScope (Manuel Vivo)
 https://medium.com/androiddevelopers/easy-coroutines-in-android- viewmodelscope-25bffb605471 • Exceed the Android Speed Limit
 https://medium.com/androiddevelopers/exceed-the-android-speed-limit- b73a0692abc1
  • 81. Referências #4 • An Early look at Kotlin Coroutine’s Flow
 https://proandroiddev.com/an-early-look-at-kotlin-coroutines- flow-62e46baa6eb0 • Coroutines on Android (Sean McQuillan)
 https://medium.com/androiddevelopers/coroutines-on-android-part-i-getting- the-background-3e0e54d20bb • Kotlin Flows and Coroutines (Roman Elizarov)
 https://medium.com/@elizarov/kotlin-flows-and-coroutines-256260fb3bdb • Simple design of Kotlin Flow (Roman Elizarov)
 https://medium.com/@elizarov/simple-design-of-kotlin-flow-4725e7398c4c • React Streams and Kotlin Flows (Roman Elizarov)
 https://medium.com/@elizarov/reactive-streams-and-kotlin-flows- bfd12772cda4