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

Android Async Talk

Android Async Talk

Most of the developers (including me of course 😅) struggle with asynchronous programming and tasks scheduling. Android developers are no exception to this!

In this talk we'll have a look at the different tools offered by the Android native programming languages (Java / Kotlin), the Android SDK, and the community (e.g.: HAMER framework, AsyncTask, Coroutines, RxJava, WorkManager, etc.) to perform asynchronous operations, schedule tasks, handle errors and deal with many of the Android OS challenges.

We’ll see pros and cons of those tools and we'll try to find an elegant, modern and efficient approach to suit our needs.

7352e4e763e3b54ac7a91f013dc7c709?s=128

Robin Caroff

November 15, 2018
Tweet

More Decks by Robin Caroff

Other Decks in Programming

Transcript

  1. The Async Talk An overview of asynchronous programming for the

    Android platform Robin Caroff @RobinCaroff
  2. Asynchronous programming

  3. Single thread

  4. Single thread

  5. Multi-threads

  6. Tools

  7. Tools

  8. Challenges

  9. Challenges • Memory management

  10. Challenges • Memory management • Concurrency

  11. Challenges • Memory management • Concurrency • Android OS

  12. A word about Android

  13. Android is an embedded system

  14. Android apps have a UI specific thread

  15. Android apps have a UI specific thread

  16. Android is a Linux fork

  17. with a specific memory management system Android is a Linux

    fork
  18. Android can doze

  19. Android can doze

  20. Tools

  21. Tools Which tool(s) should I use for which context ?

  22. Java standard library

  23. Java standard library • Threads • Executors • Concurrency tools

  24. Android SDK

  25. Android SDK • The HaMeR Framework • Async Task •

    Loaders • Services
  26. The HaMeR Framework

  27. AsyncTask

  28. AsyncTask Why all the hate ?

  29. Loaders Pros • Run on seperate threads • Simplify thread

    management with callbacks • Persist and cache results across configuration changes • Can implement an observer to monitor for changes in the underlying data source Cons • Retains reference to the activity • Implementation is not great, many callbacks • Made to manage UI/background tasks
  30. Services A Service is an application component that can perform

    long-running operations in the background, and it does not provide a user interface.
  31. Services Remember the Doze mode ?

  32. Foreground Services

  33. Scheduled Jobs

  34. Scheduled Jobs • Job Scheduler • Firebase Job Dispatcher •

    Alarm Manager • Job Intent Service • Work Manager
  35. Work Manager WorkManager aims to simplify the developer experience by

    providing a first-class API for system-driven background processing. It is intended for background jobs that should run even if the app is no longer in the foreground. Where possible, it uses JobScheduler or Firebase JobDispatcher to do the work; if your app is in the foreground, it will even try to do the work directly in your process.
  36. Work Manager

  37. Does all this stuff use multiple threads ?

  38. Rx Java/Kotlin - Rx Android

  39. Rx Java/Kotlin - Rx Android • Avoid the callback hell

    • Simple Error Handling Tool • Easy Multi-Threading • Chain jobs
  40. Rx Java/Kotlin - Rx Android userDao.getAllUsers() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<RealmResults<User>>()

    { @Override public void onError(Throwable e) { // Handle errors here } @Override public void onNext(RealmResults<User> users) { // You can access your Users } @Override public void onCompleted() { // All your user objects have been fetched. Done! } });
  41. Rx Java/Kotlin - Rx Android userDao.getAllUsers() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( users

    -> { /* Refresh UI with your new users */ }, error -> { /* Handle errors here */ }, () -> { /* All user received, remove loading indicator */} );
  42. Rx Java/Kotlin - Rx Android userDao.getAllUsers() .subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) .map(this::longTransformation) .doOnError(error

    -> { /* Log transformation error */ }) .onErrorResumeNext(error -> transformedUsersBackup()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( transformedUsers -> { /* Refresh UI with your new transformed users */ }, error -> { /* Handle errors here */ }, () -> { /* All user received and transformed, remove loading indicator */} );
  43. Rx Java/Kotlin - Rx Android userDao.getAllUsers() .subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) .map(this::longTransformation) .doOnError(error

    -> { /* Log transformation error */ }) .onErrorResumeNext(error -> transformedUsersBackup()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( transformedUsers -> { /* Refresh UI with your new transformed users */ }, error -> { /* Handle errors here */ }, () -> { /* All user received and transformed, remove loading indicator */} );
  44. Rx Java/Kotlin - Rx Android userDao.getAllUsers() .subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) .map(this::longTransformation) .doOnError(error

    -> { /* Log transformation error */ }) .onErrorResumeNext(error -> transformedUsersBackup()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( transformedUsers -> { /* Refresh UI with your new transformed users */ }, error -> { /* Handle errors here */ }, () -> { /* All user received and transformed, remove loading indicator */} );
  45. Rx Java/Kotlin - Rx Android userDao.getAllUsers() .subscribeOn(Schedulers.io()) .observeOn(Schedulers.computation()) .map(this::longTransformation) .doOnError(error

    -> { /* Log transformation error */ }) .onErrorResumeNext(error -> transformedUsersBackup()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( transformedUsers -> { /* Refresh UI with your new transformed users */ }, error -> { /* Handle errors here */ }, () -> { /* All user received and transformed, remove loading indicator */} );
  46. Schedulers • schedulers.io() -> short execution (network/DB call) • Schedulers.computation()

    • Schedulers.newThread() • Schedulers.single() • Schedulers.from(Executor executor) • AndroidSchedulers.mainThread() • …
  47. Schedulers • Schedulers.io() -> short execution (network/DB call) • Schedulers.computation()

    -> long/CPU-intensive tasks • Schedulers.newThread() • Schedulers.single() • Schedulers.from(Executor executor) • AndroidSchedulers.mainThread() • …
  48. Schedulers • Schedulers.io() -> short execution (network/DB call) • Schedulers.computation()

    -> long/CPU-intensive task • Schedulers.newThread() -> long running, isolated task • Schedulers.single() • Schedulers.from(Executor executor) • AndroidSchedulers.mainThread() • …
  49. Schedulers • Schedulers.io() • Schedulers.computation() • Schedulers.newThread() -> long running,

    isolated task • Schedulers.single() -> sequential tasks • Schedulers.from(Executor executor) • AndroidSchedulers.mainThread() • …
  50. Schedulers • Schedulers.io() -> short execution (network/DB call) • Schedulers.computation()

    -> long/CPU-intensive tasks • Schedulers.newThread() -> long running, isolated task • Schedulers.single() -> sequential tasks • Schedulers.from(Executor executor) -> custom threading logic • AndroidSchedulers.mainThread() • …
  51. Schedulers • Schedulers.io() -> short execution (network/DB call) • Schedulers.computation()

    -> long/CPU-intensive tasks • Schedulers.newThread() -> long running, isolated task • Schedulers.single() -> sequential tasks • Schedulers.from(Executor executor) -> custom threading logic • AndroidSchedulers.mainThread() -> Android main/UI thread • …
  52. Rx Java/Kotlin - Rx Android Pro and Cons

  53. Kotlin

  54. Kotlin ’s Coroutines

  55. Kotlin’s Coroutines • Coroutines are like very light-weight threads •

    Threads are used to run coroutines but one thread can execute thousands of coroutines • Coroutines can be suspended at specified suspension points • Also avoid callbacks hell and allow exceptions to be used. Write asynchronous code in continuous style • Coroutines are no longer an experimental feature
  56. Kotlin’s Coroutines val lifecycleAwareJob = Job() val uiScope = CoroutineScope(Dispatchers.Main

    + lifecycleAwareJob) uiScope.launch { try { val transformedUsers = userDao.getAllUsers() .map { it -> heavyTransformation(it) } updateUIWithUsers(transformedUsers) } catch (e: UserDaoException) { // Handle errors here } }
  57. Kotlin’s Coroutines val lifecycleAwareJob = Job() val uiScope = CoroutineScope(Dispatchers.Main

    + lifecycleAwareJob) uiScope.launch { try { val transformedUsers = userDao.getAllUsers() .map { it -> heavyTransformation(it) } updateUIWithUsers(transformedUsers) } catch (e: UserDaoException) { // Handle errors here } }
  58. Kotlin’s Coroutines val lifecycleAwareJob = Job() val uiScope = CoroutineScope(Dispatchers.Main

    + lifecycleAwareJob) uiScope.launch { try { val transformedUsers = userDao.getAllUsers() .map { it -> heavyTransformation(it) } updateUIWithUsers(transformedUsers) } catch (e: UserDaoException) { // Handle errors here } }
  59. Kotlin’s Coroutines val lifecycleAwareJob = Job() val uiScope = CoroutineScope(Dispatchers.Main

    + lifecycleAwareJob) uiScope.launch { try { val transformedUsers = userDao.getAllUsers() .map { it -> heavyTransformation(it) } updateUIWithUsers(transformedUsers) } catch (e: UserDaoException) { // Handle errors here } }
  60. Kotlin’s Coroutines val lifecycleAwareJob = Job() val uiScope = CoroutineScope(Dispatchers.Main

    + lifecycleAwareJob) uiScope.launch { try { val transformedUsers = userDao.getAllUsers() .map { it -> heavyTransformation(it) } updateUIWithUsers(transformedUsers) } catch (e: UserDaoException) { // Handle errors here } }
  61. Kotlin’s Coroutines val lifecycleAwareJob = Job() val uiScope = CoroutineScope(Dispatchers.Main

    + lifecycleAwareJob) uiScope.launch { try { val transformedUsers = userDao.getAllUsers() .map { it -> heavyTransformation(it) } updateUIWithUsers(transformedUsers) } catch (e: UserDaoException) { // Handle errors here } } suspend fun getAllUsers(): List<User> { // Async call }
  62. Kotlin’s Coroutines val lifecycleAwareJob = Job() val uiScope = CoroutineScope(Dispatchers.Main

    + lifecycleAwareJob) uiScope.launch { try { val transformedUsers = userDao.getAllUsers() .map { it -> heavyTransformation(it) } updateUIWithUsers(transformedUsers) } catch (e: UserDaoException) { // Handle errors here } }
  63. Kotlin’s Coroutines • Language: • async / await • few

    primitives • Library (kotlinx-coroutines): • launch • runBlocking • future • etc.
  64. Kotlin’s Coroutines Pro and Cons

  65. Take Away

  66. Take Away

  67. Take Away • Memory management • Let Android know you

    intentions • Separation of concerns • New tools are coming to us as restrictions are growing. Work Manager is conjunction with Kotlin’s coroutines looks very promising
  68. Robin Caroff @RobinCaroff