Slide 1

Slide 1 text

The Async Talk An overview of asynchronous programming for the Android platform Robin Caroff @RobinCaroff

Slide 2

Slide 2 text

Asynchronous programming

Slide 3

Slide 3 text

Single thread

Slide 4

Slide 4 text

Single thread

Slide 5

Slide 5 text

Multi-threads

Slide 6

Slide 6 text

Tools

Slide 7

Slide 7 text

Tools

Slide 8

Slide 8 text

Challenges

Slide 9

Slide 9 text

Challenges • Memory management

Slide 10

Slide 10 text

Challenges • Memory management • Concurrency

Slide 11

Slide 11 text

Challenges • Memory management • Concurrency • Android OS

Slide 12

Slide 12 text

A word about Android

Slide 13

Slide 13 text

Android is an embedded system

Slide 14

Slide 14 text

Android apps have a UI specific thread

Slide 15

Slide 15 text

Android apps have a UI specific thread

Slide 16

Slide 16 text

Android is a Linux fork

Slide 17

Slide 17 text

with a specific memory management system Android is a Linux fork

Slide 18

Slide 18 text

Android can doze

Slide 19

Slide 19 text

Android can doze

Slide 20

Slide 20 text

Tools

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

Java standard library

Slide 23

Slide 23 text

Java standard library • Threads • Executors • Concurrency tools

Slide 24

Slide 24 text

Android SDK

Slide 25

Slide 25 text

Android SDK • The HaMeR Framework • Async Task • Loaders • Services

Slide 26

Slide 26 text

The HaMeR Framework

Slide 27

Slide 27 text

AsyncTask

Slide 28

Slide 28 text

AsyncTask Why all the hate ?

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

Services A Service is an application component that can perform long-running operations in the background, and it does not provide a user interface.

Slide 31

Slide 31 text

Services Remember the Doze mode ?

Slide 32

Slide 32 text

Foreground Services

Slide 33

Slide 33 text

Scheduled Jobs

Slide 34

Slide 34 text

Scheduled Jobs • Job Scheduler • Firebase Job Dispatcher • Alarm Manager • Job Intent Service • Work Manager

Slide 35

Slide 35 text

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.

Slide 36

Slide 36 text

Work Manager

Slide 37

Slide 37 text

Does all this stuff use multiple threads ?

Slide 38

Slide 38 text

Rx Java/Kotlin - Rx Android

Slide 39

Slide 39 text

Rx Java/Kotlin - Rx Android • Avoid the callback hell • Simple Error Handling Tool • Easy Multi-Threading • Chain jobs

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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 */} );

Slide 42

Slide 42 text

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 */} );

Slide 43

Slide 43 text

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 */} );

Slide 44

Slide 44 text

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 */} );

Slide 45

Slide 45 text

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 */} );

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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() • …

Slide 49

Slide 49 text

Schedulers • Schedulers.io() • Schedulers.computation() • Schedulers.newThread() -> long running, isolated task • Schedulers.single() -> sequential tasks • Schedulers.from(Executor executor) • AndroidSchedulers.mainThread() • …

Slide 50

Slide 50 text

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() • …

Slide 51

Slide 51 text

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 • …

Slide 52

Slide 52 text

Rx Java/Kotlin - Rx Android Pro and Cons

Slide 53

Slide 53 text

Kotlin

Slide 54

Slide 54 text

Kotlin ’s Coroutines

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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 } }

Slide 57

Slide 57 text

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 } }

Slide 58

Slide 58 text

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 } }

Slide 59

Slide 59 text

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 } }

Slide 60

Slide 60 text

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 } }

Slide 61

Slide 61 text

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 { // Async call }

Slide 62

Slide 62 text

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 } }

Slide 63

Slide 63 text

Kotlin’s Coroutines • Language: • async / await • few primitives • Library (kotlinx-coroutines): • launch • runBlocking • future • etc.

Slide 64

Slide 64 text

Kotlin’s Coroutines Pro and Cons

Slide 65

Slide 65 text

Take Away

Slide 66

Slide 66 text

Take Away

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

Robin Caroff @RobinCaroff