Slide 1

Slide 1 text

Coroutines on the way! Armando Picón Android Engineer at Cornershop Inc. @devpicon https://medium.com/@devpicon Using Coroutines in your Android App

Slide 2

Slide 2 text

Long running tasks ● Network requests

Slide 3

Slide 3 text

Long running tasks ● Network requests ● Database operations

Slide 4

Slide 4 text

Long running tasks ● Network requests ● Database operations ● Image processing

Slide 5

Slide 5 text

Long running tasks ● Network requests ● Database operations ● Image processing ● ...and more!

Slide 6

Slide 6 text

Challenge 1: Execute on a non-UI thread

Slide 7

Slide 7 text

Challenge 1: Execute on a non-UI thread Challenge 2: Get informed when the task is done

Slide 8

Slide 8 text

Challenge 1: Execute on a non-UI thread Challenge 2: Get informed when the task is done Android solutions ● AsyncTask ● Loaders (deprecated in Android P) ● RxJava ● Thread / HandlerThread / Executor with callbacks

Slide 9

Slide 9 text

Threads and callbacks fun login(name, pass) { val thread = Thread(Runnable { requestLogin(name, pass) { result -> show(result) } }) thread.start() }

Slide 10

Slide 10 text

Threads and callbacks fun login(name, pass) { val thread = Thread(Runnable { requestLogin(name, pass) { result -> Handler(Looper.getMainLooper()) { show(result) } } }) thread.start()

Slide 11

Slide 11 text

Threads and callbacks fun login(name, pass) { requestLogin(name, pass) { result -> show(result) } }

Slide 12

Slide 12 text

onDraw onDraw onDraw requestLogin UI Thread fun login(name, pass) { requestLogin(name, pass) { result -> show(result) } }

Slide 13

Slide 13 text

onDraw onDraw onDraw requestLogin UI Thread fun login(name, pass) { requestLogin(name, pass) { result -> show(result) } }

Slide 14

Slide 14 text

onDraw onDraw onDraw requestLogin UI Thread show onDraw fun login(name, pass) { requestLogin(name, pass) { result -> show(result) } }

Slide 15

Slide 15 text

onDraw onDraw onDraw requestLogin UI Thread show onDraw fun login(name, pass) { requestLogin(name, pass) { result -> show(result) } } onDraw onDraw onDraw

Slide 16

Slide 16 text

Coroutine = suspendable computation onDraw onDraw onDraw requestLogin UI Thread show onDraw onDraw onDraw onDraw

Slide 17

Slide 17 text

Coroutine Write asynchronous code sequentially fun login(name, pass) = launch { val result = requestLogin(name, pass) show(result) }

Slide 18

Slide 18 text

Coroutine ~ lightweight thread fun login(name, pass) = launch { val result = requestLogin(name, pass) show(result) }

Slide 19

Slide 19 text

fun login(name, pass) = launch(Dispatchers.IO){ val result = requestLogin(name, pass) withContext(Dispatchers.Main) { show(result) } } Coroutine ● Not bound to a specific thread ● Complete with a result

Slide 20

Slide 20 text

fun login(name, pass) { requestLogin(name, pass) { result -> show(result) } } requestLogin Thread show Suspension point

Slide 21

Slide 21 text

suspend fun requestLogin( name: String, pass: String ): Result {...}

Slide 22

Slide 22 text

suspend fun requestLogin( name: String, pass: String ): Result {...}

Slide 23

Slide 23 text

suspend fun requestLogin( name: String, pass: String ): Result {...} Las funciones suspendidas no bloquean el hilo de invocación

Slide 24

Slide 24 text

suspend fun requestLogin( name: String, pass: String ): Result = withContext(Dispatchers.IO) { ... }

Slide 25

Slide 25 text

Dispatchers.Main ● Main thread ● Use it for: UI operations

Slide 26

Slide 26 text

Dispatchers.Default ● Common pool of shared background threads ● Use it for: computing-intensive coroutines Dispatchers.Main ● Main thread ● Use it for: UI operations

Slide 27

Slide 27 text

Dispatchers.Default ● Common pool of shared background threads ● Use it for: computing-intensive coroutines Dispatchers.IO ● Shared pool of on-demand created threads ● Use it for: IO-intensive blocking operations Dispatchers.Main ● Main thread ● Use it for: UI operations

Slide 28

Slide 28 text

Dispatchers.Default ● Common pool of shared background threads ● Use it for: computing-intensive coroutines Dispatchers.Unconfined ● Doesn’t confine the coroutine to any specific thread ● Don’t use it in code Dispatchers.IO ● Shared pool of on-demand created threads ● Use it for: IO-intensive blocking operations Dispatchers.Main ● Main thread ● Use it for: UI operations

Slide 29

Slide 29 text

suspend fun requestLogin( name: String, pass: String ): Result = withContext(Dispatchers.IO) { ... }

Slide 30

Slide 30 text

suspend fun login(name, pass) { val result = requestLogin(name, pass) show(result) } suspend fun requestLogin( name: String, pass: String ): Result = withContext(Dispatchers.IO) { ... }

Slide 31

Slide 31 text

suspend fun login(name, pass) { val authToken = authenticate() val result = requestLogin(authToken, name, pass) show(result) } Sequential

Slide 32

Slide 32 text

suspend fun login(name, pass) { val authToken = authenticate() val result = requestLogin(authToken, name, pass) show(result) } Data dependencies

Slide 33

Slide 33 text

suspend fun login(name, pass) { try { val result = requestLogin(name, pass) show(result) } catch (error: NetworkError){ } } Errors

Slide 34

Slide 34 text

Launching and cancelling coroutines Login button pressed Launch coroutine requestLogin Show login status

Slide 35

Slide 35 text

Login button pressed Launch coroutine requestLogin Show login status val job = Job() val uiScope = CoroutineScope(Dispatchers.Main + job)

Slide 36

Slide 36 text

Login button pressed Launch coroutine requestLogin Show login status val job = Job() val uiScope = CoroutineScope(Dispatchers.Main + job) fun login(username: String, pass: String ) = uiScope.launch { val result = requestLogin(name, pass) show(result) }

Slide 37

Slide 37 text

Login button pressed Launch coroutine requestLogin Show login status val job = Job() val uiScope = CoroutineScope(Dispatchers.Main + job) fun login(username: String, pass: String ) = uiScope.launch(Dispatchers.IO) { val result = requestLogin(name, pass) show(result) }

Slide 38

Slide 38 text

val job = Job() val uiScope = CoroutineScope(Dispatchers.Main + job) fun login( username: String, pass: String ) = uiScope.launch { val result = requestLogin(name, pass) show(result) } job.cancel()

Slide 39

Slide 39 text

Launching and cancelling coroutines Login button pressed Launch coroutine requestLogin Show login status Activity destroyed

Slide 40

Slide 40 text

Launching and cancelling coroutines Login button pressed Launch coroutine requestLogin Show login status ViewModel

Slide 41

Slide 41 text

Login button pressed Launch coroutine requestLogin Show login status ViewModel fun onCleared() { super.onCleared() job.cancel() }

Slide 42

Slide 42 text

class MyViewModel: ViewModel() { val viewModelJob = Job() val uiScope = CoroutineScope(Dispatchers.Main+viewModelJob) fun login( username: String, pass: String ) = uiScope.launch(Dispatchers.IO) { val result = requestLogin(name, pass) show(result) } fun onCleared() { super.onCleared() viewModelJob.cancel() } }

Slide 43

Slide 43 text

class MyViewModel: ViewModel() { val viewModelJob = Job() val uiScope = CoroutineScope(Dispatchers.Main+viewModelJob) fun login( username: String, pass: String ) = uiScope.launch(Dispatchers.IO) { val result = requestLogin(name, pass) show(result) } fun onCleared() { super.onCleared() viewModelJob.cancel() } } lifecycle-viewmodel-ktx

Slide 44

Slide 44 text

class MyViewModel: ViewModel() { fun login( username: String, pass: String ) = viewModelScope.launch(Dispatchers.IO) { val result = requestLogin(name, pass) show(result) } }

Slide 45

Slide 45 text

● Coroutines ● suspend functions ● Dispatchers ● Launching a coroutine ● Using a coroutine from ViewModels

Slide 46

Slide 46 text

● Coroutines ● suspend functions ● Dispatchers ● Launching a coroutine ● Using a coroutine from ViewModels ● Testing coroutines ● Using coroutines with other Jetpack libraries ● Channels

Slide 47

Slide 47 text

● Kotlin Official Documentation https://kotlinlang.org/docs/reference/coroutines-overview.html ● Improve app performance with Kotlin Coroutines https://developer.android.com/kotlin/coroutines ● Coroutines in Kotlin 1.3 explained: Suspending functions, contexts, builders and scopes https://antonioleiva.com/kotlin-coroutines/ ● Kotlin Coroutines by Tutorials https://store.raywenderlich.com/products/kotlin-coroutines-by-tutorials

Slide 48

Slide 48 text

Ahora es tu turno! codelabs.developers.google.com/ codelabs/ kotlin-coroutines Armando Picón Android Engineer at Cornershop Inc. @devpicon https://medium.com/@devpicon