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

More Related Content

What's hot

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
 

What's hot (20)

Reactive, component 그리고 angular2
Reactive, component 그리고  angular2Reactive, component 그리고  angular2
Reactive, component 그리고 angular2
 
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++
 
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
 
rx.js make async programming simpler
rx.js make async programming simplerrx.js make async programming simpler
rx.js make async programming simpler
 
RDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по DipRDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по Dip
 
Snapshot clone-boot-presentation-final
Snapshot clone-boot-presentation-finalSnapshot clone-boot-presentation-final
Snapshot clone-boot-presentation-final
 
Ansible fest Presentation slides
Ansible fest Presentation slidesAnsible fest Presentation slides
Ansible fest Presentation slides
 
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
 
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
 
Matthew Eernisse, NodeJs, .toster {webdev}
Matthew Eernisse, NodeJs, .toster {webdev}Matthew Eernisse, NodeJs, .toster {webdev}
Matthew Eernisse, NodeJs, .toster {webdev}
 
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
 
Rethink Async With RXJS
Rethink Async With RXJSRethink Async With RXJS
Rethink Async With RXJS
 
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
 
HAB Software Woes
HAB Software WoesHAB Software Woes
HAB Software Woes
 
Async Frontiers
Async FrontiersAsync Frontiers
Async Frontiers
 
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
 
Automating Kubernetes Environments with Ansible
Automating Kubernetes Environments with AnsibleAutomating Kubernetes Environments with Ansible
Automating Kubernetes Environments with Ansible
 
Developing JavaScript Widgets
Developing JavaScript WidgetsDeveloping JavaScript Widgets
Developing JavaScript Widgets
 
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
 
Testing Backbone applications with Jasmine
Testing Backbone applications with JasmineTesting Backbone applications with Jasmine
Testing Backbone applications with Jasmine
 

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

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
 

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

Writing Maintainable JavaScript
Writing Maintainable JavaScriptWriting Maintainable JavaScript
Writing Maintainable JavaScript
 
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
 
droidcon Transylvania - Kotlin Coroutines
droidcon Transylvania - Kotlin Coroutinesdroidcon Transylvania - Kotlin Coroutines
droidcon Transylvania - Kotlin Coroutines
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
 
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
 
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
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
 
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
 
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
 
mobl
moblmobl
mobl
 
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!
 
Introduction to Protractor
Introduction to ProtractorIntroduction to Protractor
Introduction to Protractor
 
CS101- Introduction to Computing- Lecture 35
CS101- Introduction to Computing- Lecture 35CS101- Introduction to Computing- Lecture 35
CS101- Introduction to Computing- Lecture 35
 
Cloud Orchestration with RightScale Cloud Workflow
Cloud Orchestration with RightScale Cloud WorkflowCloud Orchestration with RightScale Cloud Workflow
Cloud Orchestration with RightScale Cloud Workflow
 
Kotlin - Coroutine
Kotlin - CoroutineKotlin - Coroutine
Kotlin - Coroutine
 
Kotlin from-scratch 3 - coroutines
Kotlin from-scratch 3 - coroutinesKotlin from-scratch 3 - coroutines
Kotlin from-scratch 3 - coroutines
 
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?
 
Presto anatomy
Presto anatomyPresto anatomy
Presto anatomy
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
 

More from 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
 
Dominando o Data Binding no Android
Dominando o Data Binding no AndroidDominando o Data Binding no Android
Dominando o Data Binding no Android
Nelson Glauber Leal
 

More from Nelson Glauber Leal (20)

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
 
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
 
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
 
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)
 
Android Jetpack Compose - Turkey 2021
Android Jetpack Compose - Turkey 2021Android Jetpack Compose - Turkey 2021
Android Jetpack Compose - Turkey 2021
 
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
 
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
 
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
 
Arquitetando seu app Android com Jetpack
Arquitetando seu app Android com JetpackArquitetando seu app Android com Jetpack
Arquitetando seu app Android com Jetpack
 
Mastering Kotlin Standard Library
Mastering Kotlin Standard LibraryMastering Kotlin Standard Library
Mastering Kotlin Standard Library
 
Persisting Data on SQLite using Room
Persisting Data on SQLite using RoomPersisting Data on SQLite using Room
Persisting Data on SQLite using Room
 
Arquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com JetpackArquitetando seu aplicativo Android com Jetpack
Arquitetando seu aplicativo Android com Jetpack
 
Desenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos AndroidDesenvolvimento Moderno de Aplicativos Android
Desenvolvimento Moderno de Aplicativos Android
 
Desenvolvimento Moderno de aplicativos Android
Desenvolvimento Moderno de aplicativos AndroidDesenvolvimento Moderno de aplicativos Android
Desenvolvimento Moderno de aplicativos Android
 
Turbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com KotlinTurbinando o desenvolvimento Android com Kotlin
Turbinando o desenvolvimento Android com Kotlin
 
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
 
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
 
The world of Android Animations
The world of Android AnimationsThe world of Android Animations
The world of Android Animations
 
Android Constraint Layout
Android Constraint LayoutAndroid Constraint Layout
Android Constraint Layout
 
Dominando o Data Binding no Android
Dominando o Data Binding no AndroidDominando o Data Binding no Android
Dominando o Data Binding no Android
 

Recently uploaded

Unleashing the Future: Building a Scalable and Up-to-Date GenAI Chatbot with ...
Unleashing the Future: Building a Scalable and Up-to-Date GenAI Chatbot with ...Unleashing the Future: Building a Scalable and Up-to-Date GenAI Chatbot with ...
Unleashing the Future: Building a Scalable and Up-to-Date GenAI Chatbot with ...
confluent
 
welcome to presentation on Google Apps
welcome to   presentation on Google Appswelcome to   presentation on Google Apps
welcome to presentation on Google Apps
AsifKarimJim
 
Software development... for all? (keynote at ICSOFT'2024)
Software development... for all? (keynote at ICSOFT'2024)Software development... for all? (keynote at ICSOFT'2024)
Software development... for all? (keynote at ICSOFT'2024)
miso_uam
 
當測試開始左移
當測試開始左移當測試開始左移
當測試開始左移
Jersey (CHE-PING) Su
 
Artificial intelligence in customer services or chatbots
Artificial intelligence  in customer services or chatbotsArtificial intelligence  in customer services or chatbots
Artificial intelligence in customer services or chatbots
kayash1656
 
bangalore Girls call 👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Delivery
bangalore Girls call  👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Deliverybangalore Girls call  👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Delivery
bangalore Girls call 👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Delivery
sunilverma7884
 
Vip Girls Call ServiCe Hyderabad 0000000000 Pooja Best High Class Hyderabad A...
Vip Girls Call ServiCe Hyderabad 0000000000 Pooja Best High Class Hyderabad A...Vip Girls Call ServiCe Hyderabad 0000000000 Pooja Best High Class Hyderabad A...
Vip Girls Call ServiCe Hyderabad 0000000000 Pooja Best High Class Hyderabad A...
ashiklo9823
 
The Ultimate Guide to Phone Spy Apps: Everything You Need to Know
The Ultimate Guide to Phone Spy Apps: Everything You Need to KnowThe Ultimate Guide to Phone Spy Apps: Everything You Need to Know
The Ultimate Guide to Phone Spy Apps: Everything You Need to Know
onemonitarsoftware
 
Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...
Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...
Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...
kiara pandey
 
React Native vs Flutter - SSTech System
React Native vs Flutter  - SSTech SystemReact Native vs Flutter  - SSTech System
React Native vs Flutter - SSTech System
SSTech System
 
Celebrity Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Servic...
Celebrity Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Servic...Celebrity Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Servic...
Celebrity Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Servic...
45unexpected
 
Prada Group Reports Strong Growth in First Quarter …
Prada Group Reports Strong Growth in First Quarter …Prada Group Reports Strong Growth in First Quarter …
Prada Group Reports Strong Growth in First Quarter …
908dutch
 
TEQnation 2024: Sustainable Software: May the Green Code Be with You
TEQnation 2024: Sustainable Software: May the Green Code Be with YouTEQnation 2024: Sustainable Software: May the Green Code Be with You
TEQnation 2024: Sustainable Software: May the Green Code Be with You
marcofolio
 
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in CityGirls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
neshakor5152
 
Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...
Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...
Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...
shanihomely
 
AI - Your Startup Sidekick (Leveraging AI to Bootstrap a Lean Startup).pdf
AI - Your Startup Sidekick (Leveraging AI to Bootstrap a Lean Startup).pdfAI - Your Startup Sidekick (Leveraging AI to Bootstrap a Lean Startup).pdf
AI - Your Startup Sidekick (Leveraging AI to Bootstrap a Lean Startup).pdf
Daniel Zivkovic
 
Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...
Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...
Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...
87tomato
 
Top Chinese Government-backed APT Groups
Top Chinese Government-backed APT GroupsTop Chinese Government-backed APT Groups
Top Chinese Government-backed APT Groups
SOCRadar
 
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docxComprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Aardwolf Security
 
Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...
Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...
Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...
OnePlan Solutions
 

Recently uploaded (20)

Unleashing the Future: Building a Scalable and Up-to-Date GenAI Chatbot with ...
Unleashing the Future: Building a Scalable and Up-to-Date GenAI Chatbot with ...Unleashing the Future: Building a Scalable and Up-to-Date GenAI Chatbot with ...
Unleashing the Future: Building a Scalable and Up-to-Date GenAI Chatbot with ...
 
welcome to presentation on Google Apps
welcome to   presentation on Google Appswelcome to   presentation on Google Apps
welcome to presentation on Google Apps
 
Software development... for all? (keynote at ICSOFT'2024)
Software development... for all? (keynote at ICSOFT'2024)Software development... for all? (keynote at ICSOFT'2024)
Software development... for all? (keynote at ICSOFT'2024)
 
當測試開始左移
當測試開始左移當測試開始左移
當測試開始左移
 
Artificial intelligence in customer services or chatbots
Artificial intelligence  in customer services or chatbotsArtificial intelligence  in customer services or chatbots
Artificial intelligence in customer services or chatbots
 
bangalore Girls call 👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Delivery
bangalore Girls call  👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Deliverybangalore Girls call  👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Delivery
bangalore Girls call 👀 XXXXXXXXXXX 👀 Rs.9.5 K Cash Payment With Room Delivery
 
Vip Girls Call ServiCe Hyderabad 0000000000 Pooja Best High Class Hyderabad A...
Vip Girls Call ServiCe Hyderabad 0000000000 Pooja Best High Class Hyderabad A...Vip Girls Call ServiCe Hyderabad 0000000000 Pooja Best High Class Hyderabad A...
Vip Girls Call ServiCe Hyderabad 0000000000 Pooja Best High Class Hyderabad A...
 
The Ultimate Guide to Phone Spy Apps: Everything You Need to Know
The Ultimate Guide to Phone Spy Apps: Everything You Need to KnowThe Ultimate Guide to Phone Spy Apps: Everything You Need to Know
The Ultimate Guide to Phone Spy Apps: Everything You Need to Know
 
Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...
Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...
Celebrity Girls Call Mumbai 9930687706 Unlimited Short Providing Girls Servic...
 
React Native vs Flutter - SSTech System
React Native vs Flutter  - SSTech SystemReact Native vs Flutter  - SSTech System
React Native vs Flutter - SSTech System
 
Celebrity Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Servic...
Celebrity Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Servic...Celebrity Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Servic...
Celebrity Girls Call Mumbai 9920725232 Unlimited Short Providing Girls Servic...
 
Prada Group Reports Strong Growth in First Quarter …
Prada Group Reports Strong Growth in First Quarter …Prada Group Reports Strong Growth in First Quarter …
Prada Group Reports Strong Growth in First Quarter …
 
TEQnation 2024: Sustainable Software: May the Green Code Be with You
TEQnation 2024: Sustainable Software: May the Green Code Be with YouTEQnation 2024: Sustainable Software: May the Green Code Be with You
TEQnation 2024: Sustainable Software: May the Green Code Be with You
 
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in CityGirls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
Girls Call Mysore 000XX00000 Provide Best And Top Girl Service And No1 in City
 
Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...
Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...
Russian Girls Call Mumbai 🎈🔥9930687706 🔥💋🎈 Provide Best And Top Girl Service ...
 
AI - Your Startup Sidekick (Leveraging AI to Bootstrap a Lean Startup).pdf
AI - Your Startup Sidekick (Leveraging AI to Bootstrap a Lean Startup).pdfAI - Your Startup Sidekick (Leveraging AI to Bootstrap a Lean Startup).pdf
AI - Your Startup Sidekick (Leveraging AI to Bootstrap a Lean Startup).pdf
 
Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...
Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...
Verified Girls Call Mumbai 👀 9820252231 👀 Cash Payment With Room DeliveryDeli...
 
Top Chinese Government-backed APT Groups
Top Chinese Government-backed APT GroupsTop Chinese Government-backed APT Groups
Top Chinese Government-backed APT Groups
 
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docxComprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
Comprehensive Vulnerability Assessments Process _ Aardwolf Security.docx
 
Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...
Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...
Maximizing Efficiency and Profitability: Optimizing Data Systems, Enhancing C...
 

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