Powerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost Lover
Android Jetpack + Coroutines: To infinity and beyond
1. ANDROID JETPACK + COROUTINES:
TO INFINITEAND BEYOND
Ramon Ribeiro Rabello
2. Hi, I’m Ramon Rabello | Bio
11 years in Android
GDG Floripa Organizer
❤ Communities
Star Wars fan, I am!
Master Software Engineer |
about.me/ramonrabello
Beer lover
3. Come meet us! | ArcTouch Brasil at TDC
"Ask the Experts" Android session
Ramon & Paula - 13:10
9. Android Jetpack | Overview
Simplify complex tasks
A collection of Android software components
Follow best practices
Free you from writing boilerplate code
Comprises the androidx.* packages
10. Android Jetpack | Overview
Simplify complex tasks
A collection of Android software components
Follow best practices
Free you from writing boilerplate code
Comprises the androidx.* packages
11. Android Jetpack | Overview
Simplify complex tasks
A collection of Android software components
Follow best practices
Free you from writing boilerplate code
Comprises the androidx.* packages
12. Android Jetpack | Overview
Simplify complex tasks
A collection of Android software components
Follow best practices
Free you from writing boilerplate code
Comprises the androidx.* packages
13. Android Jetpack | Overview
Simplify complex tasks
A collection of Android software components
Follow best practices
Free you from writing boilerplate code
Comprises the androidx.* packages
22. androidx | Migrating to androidx
Manually
Automagically
Add both androidX=true and enableJetfier=true to
gradle.properties file
In Android Studio 3.2.1+: Refactor -> Migrate to AndroidX…
30. Architecture Components | The Big Picture
Activity/Fragment
LiveData
LiveData
Repository
ViewModel
Local Data Source
Room
Remote Data Source
Retrofit
SQLite API
45. Coroutines | Brief history
Founded on Continuation principle
Concept first coined in 1958 by Melvin Conway
Like threads, but far away more lightweight
Tasks that can be suspended and resumed
Stable as of Kotlin 1.3
https://github.com/Kotlin/kotlinx.coroutines
46. Coroutines | Brief history
Founded on Continuation principle
Concept first coined in 1958 by Melvin Conway
Like threads, but far away more lightweight
Tasks that can be suspended and resumed
Stable as of Kotlin 1.3
https://github.com/Kotlin/kotlinx.coroutines
47. Coroutines | Brief history
Founded on Continuation principle
Concept first coined in 1958 by Melvin Conway
Like threads, but far away more lightweight
Tasks that can be suspended and resumed
Stable as of Kotlin 1.3
https://github.com/Kotlin/kotlinx.coroutines
48. Coroutines | Brief history
Founded on Continuation principle
Concept first coined in 1958 by Melvin Conway
Like threads, but far away more lightweight
Tasks that can be suspended and resumed
Stable as of Kotlin 1.3
https://github.com/Kotlin/kotlinx.coroutines
49. Coroutines | Brief history
Founded on Continuation principle
Concept first coined in 1958 by Melvin Conway
Like threads, but far away more lightweight
Tasks that can be suspended and resumed
Stable as of Kotlin 1.3
https://github.com/Kotlin/kotlinx.coroutines
50. Coroutines | Motivation
object: LoadingTask : AsyncTask() {
override fun doInBackground() {…}
override fun onPostExecute() {…}
}
56. Coroutines | Building blocks
Coroutine builder
Coroutine context
suspend function
builders to launch a coroutine
coroutine dispatchers
mark a suspension point
57. Coroutine builder | launch - synchronous coroutine
fun loadTrending() = launch {
_uiStateEvent.postValue(UiState.Loading)
val result = async { repository.loadTrending() }.await()
_trendingData.postValue(Result.success(result))
_uiStateEvent.postValue(UiState.Loaded)
}
58. Coroutine builder | launch - synchronous coroutine
fun loadTrending() = launch {
_uiStateEvent.postValue(UiState.Loading)
val result = async { repository.loadTrending() }.await()
_trendingData.postValue(Result.success(result))
_uiStateEvent.postValue(UiState.Loaded)
} Job
59. Coroutine builder | async - Loading coroutines in parallel
fun loadTrending() = launch {
_uiStateEvent.postValue(UiState.Loading)
val local = async { /* load local trending */ }.await()
val remote = async { /* load remote trending */ }.await()
val result = local + remote
_trendingData.postValue(Result.success(result))
_uiStateEvent.postValue(UiState.Loaded)
}
60. Coroutine builder | async - Loading coroutines in parallel
fun loadTrending() = launch {
_uiStateEvent.postValue(UiState.Loading)
val local = async { /* load local trending */ }.await()
val remote = async { /* load remote trending */ }.await()
val result = local + remote
_trendingData.postValue(Result.success(result))
_uiStateEvent.postValue(UiState.Loaded)
}
Deferred<T>
Deferred<T>
61. Coroutine context | Dispatchers
Main
IO
Default
Unconfined
UI Contexts
I/O operations
Uses heavy CPU
computation
No need to run on specific
context
62. Coroutine builder | withContext - Switching contexts
val uiContext: CoroutineContext = Dispatchers.Main
val ioContext: CoroutineContext = Dispatchers.IO
fun loadTrending() = launch(uiContext) {
_uiStateEvent.postValue(UiState.Loading)
val result = withContext(ioContext){ repository.loadTrending() }
_trendingData.postValue(Result.success(result))
_uiStateEvent.postValue(UiState.Loaded)
}
63. Coroutine builder | withContext - Switching contexts
val uiContext: CoroutineContext = Dispatchers.Main
val ioContext: CoroutineContext = Dispatchers.IO
fun loadTrending() = launch(uiContext) {
_uiStateEvent.postValue(UiState.Loading)
val result = withContext(ioContext){ repository.loadTrending() }
_trendingData.postValue(Result.success(result))
_uiStateEvent.postValue(UiState.Loaded)
}
parent coroutine
64. Coroutine builder | withContext - Switching contexts
val uiContext: CoroutineContext = Dispatchers.Main
val ioContext: CoroutineContext = Dispatchers.IO
fun loadTrending() = launch(uiContext) {
_uiStateEvent.postValue(UiState.Loading)
val result = withContext(ioContext){ repository.loadTrending() }
_trendingData.postValue(Result.success(result))
_uiStateEvent.postValue(UiState.Loaded)
}
Child coroutine
parent coroutine
65. Coroutine builder | withContext - Switching contexts
val uiContext: CoroutineContext = Dispatchers.Main
val ioContext: CoroutineContext = Dispatchers.IO
fun loadTrending() = launch(uiContext) {
_uiStateEvent.postValue(UiState.Loading)
val result = withContext(ioContext){ repository.loadTrending() }
_trendingData.postValue(Result.success(result))
_uiStateEvent.postValue(UiState.Loaded)
}
Child coroutine
parent coroutine
66. Coroutine builder | withContext - Switching contexts
val uiContext: CoroutineContext = Dispatchers.Main
val ioContext: CoroutineContext = Dispatchers.IO
fun loadTrending() = launch(uiContext) {
_uiStateEvent.postValue(UiState.Loading)
val result = withContext(ioContext){ repository.loadTrending() }
_trendingData.postValue(Result.success(result))
_uiStateEvent.postValue(UiState.Loaded)
}
Child coroutine
parent coroutine
67. Coroutines | suspending a point of execution
suspend fun loadTrending(){…}
⚠
Suspended coroutines must be called only from other
suspended ones.
68. Coroutines | suspend - suspending all the things!
suspend fun loadTrending() = trendingApi.loadTrending()
RemoteTrendingDataSource.kt
suspend fun loadTrending() = trendingDao.loadTrending()
LocalTrendingDataSource.kt
suspend fun loadTrending() =
localDataSource.loadTrending().await() +
remoteDataSource.loadTrending().await()
TrendingRepository.kt
fun loadTrending() = launch(uiContext) {
val result = async { repository.loadTrending() }
}
TrendingViewModel.kt