Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android + Kotlin Coroutines: Async de um jeito "diferente"

Android + Kotlin Coroutines: Async de um jeito "diferente"

Slides do um talk realizado no Android Meetup SP, que aconteceu em São Paulo, no dia 6 de Março de 2018.

O talk foi sobre o que são e como utilizar Kotlin Coroutines no Android de um jeito simples e prático.

Link: https://www.meetup.com/pt-BR/GDG-SP/events/248170951/

Walmyr Carvalho

March 06, 2018
Tweet

More Decks by Walmyr Carvalho

Other Decks in Technology

Transcript

  1. Walmyr Carvalho
    #AndroidMeetupSP
    Android + Kotlin Coroutines
    Async de um jeito "diferente"
    +

    View full-size slide

  2. Walmyr Carvalho
    @walmyrcarvalho

    View full-size slide

  3. Aplicações modernas para Android
    vão precisar fazer uso de alguma
    operação assíncrona em algum momento.

    View full-size slide

  4. E temos algumas várias (muitas)
    formas de se fazer isso,
    cada uma com um propósito:

    View full-size slide

  5. AsyncTask
    Loader
    Service
    JobScheduler/JobSchedulerCompat
    IntentService
    Thread
    FutureTask
    Firebase JobDispatcher

    View full-size slide

  6. E hoje temos uma biblioteca “vencedora” no que diz
    respeito a operações assíncronas no Android em geral.

    View full-size slide

  7. Resumindo:
    Temos muitas opções mas todas elas tem algum ponto
    "negativo” em algum aspecto.

    View full-size slide

  8. Kotlin Coroutines

    View full-size slide

  9. Coroutines no Kotlin são threads "mais leves”,
    com uma sintaxe de código assíncrono tão
    direta quanto a de um código síncrono.

    View full-size slide

  10. Elas são tipos de funções chamadas suspending functions,
    e tem seus métodos marcados com a palavra chave suspend.

    View full-size slide

  11. suspend fun getUser(userId: String): User {
    // return an User object
    }

    View full-size slide

  12. Na prática, a utilização duma coroutine seria:

    View full-size slide

  13. // roda o código em uma thread pool em background
    fun asyncOverlay() = async(CommonPool) {
    // inicia duas operações assíncronas
    val original = asyncLoadImage("original")
    val overlay = asyncLoadImage("overlay")
    // e aplica o overlay para os dois resultados
    applyOverlay(original.await(), overlay.await())
    }
    // executa a coroutine no contexto de UI
    launch(UI) {
    val image = asyncOverlay().await()
    showImage(image)
    }

    View full-size slide

  14. O launch é a maneira mais simples de se criar uma coroutine
    numa thread em background, tendo um Job (uma task em
    background, basicamente) como sua referência para si.

    View full-size slide

  15. public actual fun launch(
    context: CoroutineContext = DefaultDispatcher,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    parent: Job? = null,
    block: suspend CoroutineScope.() -> Unit
    ): Job

    View full-size slide

  16. Conceitualmente, o async é similar ao launch,
    mas a diferença deles é que o async retorna um Deferred,
    que é basicamente uma future (ou promise).

    View full-size slide

  17. public actual fun async(
    context: CoroutineContext = DefaultDispatcher,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    parent: Job? = null,
    block: suspend CoroutineScope.() -> T
    ): Deferred

    View full-size slide

  18. O CoroutineContext diz respeito a qual thread ela irá
    rodar: background (CommonPool) ou UI.

    View full-size slide

  19. Tecnicamente, um Deferred é um Job, só que com uma
    future com uma promessa de entregar um valor em breve.

    View full-size slide

  20. Ou seja: No async você tem a mesma
    funcionalidade do launch, mas com a diferença
    que ele retorna um valor no .await():

    View full-size slide

  21. fun getUser(userId: String): User = async {
    // return User
    }
    launch(UI) {
    val user = getUser(id).await()
    navigateToUserDetail(user)
    }

    View full-size slide

  22. Também é possível rodar alguma operação bloqueando
    completamente a thread, utilizando o runBlocking,
    mas não é algo muito necessário no Android:

    View full-size slide

  23. runBlocking {
    delay(2000)
    }

    View full-size slide

  24. Resumindo:
    Se não faço questão de um callback -> launch
    Se eu preciso esperar uma future (Deferred) -> async
    Se eu preciso bloquear minha thread -> runBlocking

    View full-size slide

  25. Também é possível cancelar um Job (ou um Deferred),
    e checar o estado dele:

    View full-size slide

  26. val job = launch {
    // do your stuff
    }
    job.cancel()
    val job = launch {
    while (isActive){
    //do your stuff
    }
    }

    View full-size slide

  27. Configurando no seu projeto

    View full-size slide

  28. dependencies {
    classpath 'com.android.tools.build:gradle:3.0.1'
    classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.30'
    }
    build.gradle

    View full-size slide

  29. dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:1.2.30"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.5"
    implementation “org.jetbrains.kotlinx:kotlinx-coroutines-android:0.22.5"
    }
    app/build.gradle

    View full-size slide

  30. kotlin {
    experimental {
    coroutines "enable"
    }
    }
    app/build.gradle

    View full-size slide

  31. Exemplos de uso no Android

    View full-size slide

  32. Kotlin Coroutines for Retrofit
    github.com/gildor/kotlin-coroutines-retrofit

    View full-size slide

  33. fun Call.await(): T

    View full-size slide

  34. fun main(args: Array) = runBlocking {
    try {
    val user: User = api.getUser("username").await()
    println("User ${user.name} loaded")
    } catch (e: HttpException) {
    println("exception${e.code()}", e)
    } catch (e: Throwable) {
    println("Something broken", e)
    }
    }

    View full-size slide

  35. Retrofit 2 Coroutine Adapter (Experimental) - Jake Wharton
    github.com/JakeWharton/retrofit2-kotlin-coroutines-adapter

    View full-size slide

  36. val retrofit = Retrofit.Builder()
    .baseUrl("https://example.com/")
    .addCallAdapterFactory(CoroutineCallAdapterFactory())
    .build()

    View full-size slide

  37. interface MyService {
    @GET("/user")
    fun getUser(): Deferred
    // ou
    @GET("/user")
    fun getUser(): Deferred>
    }

    View full-size slide

  38. PEKO (PErmissions in KOtlin)
    github.com/JakeWharton/retrofit2-kotlin-coroutines-adapter

    View full-size slide

  39. launch (UI) {
    val result = Peko.requestPermissions(this, Manifest.permission.BLUETOOTH).await()
    if (result.grantedPermissions.contains(Manifest.permission.BLUETOOTH)) {
    // permissão concedida
    } else {
    // nope
    }
    }

    View full-size slide

  40. Links úteis

    View full-size slide

  41. Coroutines - Documentação Oficial
    kotlinlang.org/docs/reference/coroutines.html

    View full-size slide

  42. Deep Dives into Coroutines on JVM - Roman Elizarov (KotlinConf 2017)
    goo.gl/Vt22LK

    View full-size slide

  43. Community - Kotlin
    kotlinlang.org/community/

    View full-size slide

  44. Kotlin - Android Developers
    developer.android.com/kotlin

    View full-size slide

  45. Kotlin Meetup SP
    meetup.com/kotlin-meetup-sp

    View full-size slide

  46. Android Dev BR
    slack.androiddevbr.org

    View full-size slide

  47. Muito obrigado!

    View full-size slide