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

Android Assíncrono

Android Assíncrono

Apresentada na trilha Android do TDC São Paulo 2018

Rafael Toledo

July 18, 2018
Tweet

More Decks by Rafael Toledo

Other Decks in Programming

Transcript

  1. Por que é um problema? 6 • Diminui a legibilidade

    do código • Mais difícil de debugar • Pode trazer problemas de concorrência • Pode trazer problemas de desempenho
  2. Abordagens "clássicas" e seus problemas 9 • AsyncTask - dificuldade

    em lidar com lifecycle, facilidade em causar leaks de memória • IntentService - API verbosa e a necessidade de se criar um serviço para cada tarefa (ou uma tarefa com muita lógica) • Threads - pouco controle (ou controle demais?)
  3. RxJava - o que é? 11 • Biblioteca parte das

    Reactive Extensions • Mais que uma biblioteca de assincronismo • Introduz paradigmas de programação reativa funcional • Tem uma curva de aprendizado íngreme
  4. 13

  5. RxJava - quando eu uso? 14 • Múltiplas fontes de

    dados que precisam ser trabalhadas juntas • Fluxo contínuo de dados • UI dinâmica (reativa)
  6. Kotlin Coroutines - o que é? 16 • Desde o

    Kotlin 1.1 • Permite escrever código assíncrono de forma sequencial • Evita complexidade • Evita o famoso "callback hell"
  7. Kotlin Coroutines - quando eu uso? 17 • Processamento assíncrono

    fora da main thread ◦ Requests ◦ I/O ◦ Processamento • kotlinx-coroutines-android permite fazer a mudança para a main thread!
  8. Kotlin Coroutines 18 // Expectativa fun performRequest() { view.showLoading() val

    result = api.fetch() view.hideLoading() textView.setText(result.data) }
  9. 19

  10. Kotlin Coroutines 20 fun performRequest() = launch(UI) { view.showLoading() val

    result = withContext(CommonPool) { api.fetch() } view.hideLoading() textView.setText(result.data) }
  11. Kotlin Coroutines 21 fun performRequest() = launch(UI) { view.showLoading() val

    result = withContext(CommonPool) { api.fetch() } view.hideLoading() textView.setText(result.data) }
  12. Kotlin Coroutines 22 fun performRequest() = launch(UI) { view.showLoading() val

    result = withContext(CommonPool) { api.fetch() } view.hideLoading() textView.setText(result.data) }
  13. Kotlin Coroutines 23 fun performRequest() = launch(UI) { view.showLoading() val

    result = withContext(CommonPool) { api.fetch() } view.hideLoading() textView.setText(result.data) }
  14. Kotlin Coroutines - Contextos 24 • UI: executa na main

    thread • CommonPool: executa em uma thread em background • Unconfined: executa na mesma thread
  15. Kotlin Coroutines 25 fun performRequest() = launch(UI) { view.showLoading() //

    Joga exception...? val result = withContext(CommonPool) { api.fetch() } view.hideLoading() textView.setText(result.data) }
  16. 26

  17. Kotlin Coroutines 27 fun performRequest() = launch(UI) { view.showLoading() try

    { val result = withContext(CommonPool) { api.fetch() } textView.setText(result.data) } catch (exception: IOException) { textView.setText(exception.message) } view.hideLoading() }
  18. Kotlin Coroutines 29 fun performRequest() = async(UI) { view.showLoading() try

    { val task = async(CommonPool) { api.fetch() } val result = task.await() textView.setText(result.data) } catch (exception: IOException) { textView.setText(exception.message) } view.hideLoading() }
  19. Kotlin Coroutines 30 fun performRequest() = async(UI) { view.showLoading() try

    { val task = async(CommonPool) { api.fetch() } val result = task.await() textView.setText(result.data) } catch (exception: IOException) { textView.setText(exception.message) } view.hideLoading() }
  20. 32

  21. WorkManager - quando usar? Tarefas "adiáveis" - precisam ser executadas,

    mesmo se o app for fechado, mas não precisam ser executadas em um momento exato É uma solução consistente semelhante ao JobScheduler Ex: upload de logs, sincronização com servidor, tarefas de processamento pesado, que podem demorar bastante 34
  22. WorkManager Utiliza em sua implementação JobScheduler, Firebase JobDispatcher ou AlarmManager

    // Atualmente na versão 1.0.0-alpha04 android.arch.work:work-runtime :work-runtime-ktx :work-testing :work-firebase 35
  23. WorkManager - API 37 class FirstWorker : Worker() { override

    fun doWork(): Result { return Result.SUCCESS } }
  24. WorkManager - API 38 class FirstWorker : Worker() { override

    fun doWork(): Result { return Result.FAILURE } }
  25. WorkManager - API 39 class FirstWorker : Worker() { override

    fun doWork(): Result { return Result.RETRY } }
  26. WorkManager - API 40 class FirstWorker : Worker() { override

    fun doWork(): Result { inputData applicationContext } }
  27. WorkManager - Agendamento Simples 44 val firstWork = OneTimeWorkRequestBuilder<FirstWorker>() .setInputData(Data.Builder()

    .putString("key", "value") .build()) .build() WorkManager.getInstance()?.enqueue(firstWork)
  28. WorkManager - Agendamento Simples 45 val firstWork = OneTimeWorkRequestBuilder<FirstWorker>() .setInputData(mapOf("value"

    to "key").toWorkData()) .build() WorkManager.getInstance()?.enqueue(firstWork) // Dentro do método doWork() inputData.getString("key", "Default Value")
  29. WorkManager - Constraints 46 val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .setRequiresCharging(true)

    .setRequiresBatteryNotLow(true) .build() val firstWork = OneTimeWorkRequestBuilder<FirstWorker>() .setConstraints(constraints) .setInputData(mapOf("value" to "key").toWorkData()) .build()
  30. WorkManager - Constraints 47 val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .setRequiresCharging(true)

    .setRequiresBatteryNotLow(true) .build() val firstWork = OneTimeWorkRequestBuilder<FirstWorker>() .setConstraints(constraints) .setInputData(mapOf("value" to "key").toWorkData()) .build()
  31. WorkManager - Agendamento Periódico 48 // work-runtime-ktx val periodicWork =

    PeriodicWorkRequestBuilder<FirstWorker>(1, TimeUnit.DAYS).build() WorkManager.getInstance()?.enqueue(periodicWork)
  32. WorkManager - Testes 49 @Before fun setUp() { WorkManagerTestInitHelper.initializeTestWorkManager( InstrumentationRegistry.getTargetContext())

    // ... } @Test fun checkIfJobIsDone() { val worker = ... WorkManager.getInstance()?.enqueue(worker) WorkManagerTestInitHelper.getTestDriver().setAllConstraintsMet(worker.id) // Assertions }
  33. Worker - pontos importantes • é executado após o sistema

    obter um wakelock - não é necessário requisitar • é executado numa thread em background • não deve iniciar nenhuma nova thread - deve retornar um status • não pode rodar pra sempre - ~10 minutos 51
  34. Links KOTLIN COROUTINES https://github.com/Kotlin/kotlinx.coroutines A GUIDE TO KOTLIN COROUTINES BY

    EXAMPLE https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md WORKMANAGER https://developer.android.com/topic/libraries/architecture/workmanager 52
  35. Links - vídeos INTRODUCTION TO COROUTINES https://www.youtube.com/watch?v=_hfBv0a09Jc DEEP DIVE INTO

    COROUTINES ON JVM https://www.youtube.com/watch?v=YrrUCSi72E8 EASY BACKGROUND PROCESSING WITH WORKMANAGER https://www.youtube.com/watch?v=IrKoBFLwTN0 53