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

Kotlin Coroutines: Let it async in • Bapusaheb Patil • BlrKotlin's 9th Meetup

Kotlin Coroutines: Let it async in • Bapusaheb Patil • BlrKotlin's 9th Meetup

This is the presentation to my talk, titled 'Kotlin Coroutines: Let it async in' in BlrKotlin's 9th Meetup.
October 27th, 2018.

Bapusaheb Patil

October 27, 2018
Tweet

More Decks by Bapusaheb Patil

Other Decks in Programming

Transcript

  1. Kotlin Coroutines: Let it async in Bapusaheb Patil Google Certified

    Android Developer, IDF Certified UX Designer www.bapspatil.com
  2. bapspatil.com Who this talk is for… • Kotlin basics •

    Asynchronous programming basics • Anyone who can handle lame jokes & memes
  3. bapspatil.com • XML parsing • View inflation • View measurement

    • View positioning Your app on the Main Thread
  4. bapspatil.com AsyncTask class MyTask: AsyncTask<URL, Void, String>() { override fun

    doInBackground(vararg params: URL?): String? { ...... } override fun onPostExecute(result: String?) { super.onPostExecute(result) ...... } }
  5. bapspatil.com Loader class MyLoader(context: Context, private val url: URL) :

    AsyncTaskLoader<String>(context) { override fun onStartLoading() { forceLoad() } override fun loadInBackground(): String? { ......... } }
  6. bapspatil.com CompletableFuture var completableFuture = CompletableFuture.supplyAsync(object:Supplier<String>() { fun get():String {

    try { doLongTask() } catch (e:InterruptedException) { throw IllegalStateException(e) } return "Result of the asynchronous computation" } }) val result = completableFuture.get() minSdk >= 24
  7. bapspatil.com IntentService class MyService : IntentService() { override fun onHandleIntent(Intent

    intent) { ...... } } <service android:name=”.MyService” android:exported=false />
  8. suspend fun doLongTask(): Unit? { ...... } fun doLongTask(): Unit?

    { ...... } Suspending function bapspatil.com
  9. val job = launch { doLongTask() } job.join() If you

    need to suspend the coroutine job.cancel() Job bapspatil.com
  10. async { doLongTask() } suspend fun doLongTask(): String? { ......

    return resultString } // Return something in the future Deferred<String> bapspatil.com
  11. val deferred = async { doLongTask() } val result =

    deferred.await() deferred.cancel() Deferred<String> bapspatil.com
  12. suspend fun fetchMovieData() { val popularMovies = apiService.getMoviesByType(“POPULAR”) val topRatedMovies

    = apiService.getMoviesByType(“TOP_RATED”) val upcomingMovies = apiService.getMoviesByType(“UPCOMING”) val nowPlayingMovies = apiService.getMoviesByType(“NOW_PLAYING”) val allMovies = mergeAllMovies(popularMovies, topRatedMovies, upcomingMovies, nowPlayingMovies) database.saveToDb(allMovies) } Takes 4.8 seconds bapspatil.com
  13. suspend fun fetchMovieData() { val popularDeferred = async { apiService.getMoviesByType(“POPULAR”)

    } val topRatedDeferred = async { apiService.getMoviesByType(“TOP_RATED”) } val upcomingDeferred = async { apiService.getMoviesByType(“UPCOMING”) } val nowPlayingDeferred = async { apiService.getMoviesByType(“NOW_PLAYING”) } val popularMovies = popularDeferred.await() val topRatedMovies = topRatedDeferred.await() val upcomingMovies = upcomingDeferred.await() val nowPlayingMovies = nowPlayingDeferred.await() val allMovies = mergeAllMovies(popularMovies, topRatedMovies, upcomingMovies, nowPlayingMovies) database.saveToDb(allMovies) } bapspatil.com
  14. suspend fun fetchMovieData() { val popularDeferred = async { apiService.getMoviesByType(“POPULAR”)

    } val topRatedDeferred = async { apiService.getMoviesByType(“TOP_RATED”) } val upcomingDeferred = async { apiService.getMoviesByType(“UPCOMING”) } val nowPlayingDeferred = async { apiService.getMoviesByType(“NOW_PLAYING”) } val allMovies = mergeAllMovies(popularDeferred.await(), topRatedDeferred.await(), upcomingDeferred.await(), nowPlayingDeferred.await()) database.saveToDb(allMovies) } Takes 2.6 seconds bapspatil.com
  15. suspend fun fetchMovieData() { val popularDeferred = async { apiService.getMoviesByType(“POPULAR”)

    } val topRatedDeferred = async { apiService.getMoviesByType(“TOP_RATED”) } val upcomingDeferred = async { apiService.getMoviesByType(“UPCOMING”) } val nowPlayingDeferred = async { apiService.getMoviesByType(“NOW_PLAYING”) } val allMovies = mergeAllMovies(popularDeferred.await(), topRatedDeferred.await(), upcomingDeferred.await(), nowPlayingDeferred.await()) database.saveToDb(allMovies) // Update the UI from the suspending function runOnUiThread { updateUI(allMovies) } } Updating the UI... bapspatil.com
  16. launch { doSomeWork() launch { val result = async {

    getSomeResult() } doMoreWork(result.await()) } launch { doEvenMoreWork() } } bapspatil.com
  17. class MyActivity : AppCompatActivity() { private val compositeDisposable = CompositeDisposable()

    override fun onCreate() { // ... compositeDisposable.add(getFirstObservable()) compositeDisposable.add(getSecondObservable()) } override fun onDestroy() { super.onDestroy() compositeDisposable.clear() } } bapspatil.com
  18. class MyActivity : AppCompatActivity() { private var firstJob: Job? =

    null private var secondJob: Job? = null override fun onCreate() { // ... firstJob = launch { doSomeWork() } secondJob = launch { doSomeMoreWork() } } override fun onDestroy() { super.onDestroy() firstJob.cancel() secondJob.cancel() } } bapspatil.com
  19. class MyActivity : AppCompatActivity() { lateinit var activityJob: Job override

    fun onCreate() { activityJob = Job() val outerJob = launch(parent = activityJob) { val firstJob = launch { doSomeWork() } val secondJob = launch { doSomeMoreWork() } } } override fun onDestroy() { super.onDestroy() activityJob.cancel() } } bapspatil.com
  20. val outerJob = launch(parent = activityJob) { val firstJob =

    launch { doSomeWork() } val secondJob = launch { doSomeMoreWork() } } • outerJob gets canceled. • firstJob & secondJob do not! bapspatil.com
  21. val outerJob = launch(parent = activityJob) { val firstJob =

    launch { doSomeWork() } val secondJob = launch { doSomeMoreWork() } } bapspatil.com
  22. val outerJob = launch(parent = activityJob) { val firstJob =

    launch(parent = activityJob) { doSomeWork() } val secondJob = launch(parent = activityJob) { doSomeMoreWork() } } bapspatil.com
  23. launch(parent = activityJob) Restricts the scope of the coroutine to

    Activity’s lifecycle, but not its child coroutines. bapspatil.com
  24. Deprecated launch(parent = activityJob) Restricts the scope of the coroutine

    to Activity’s lifecycle, but not its child coroutines. Coroutines 0.26+ → Forget it. bapspatil.com
  25. class MyActivity : AppCompatActivity(), CoroutineScope { lateinit var activityJob: Job

    override val coroutineContext: CoroutineContext get() = activityJob + Dispatchers.Main override fun onCreate() { // ... activityJob = Job() val outerJob = this.launch(context = coroutineContext) { val firstJob = launch { doSomeWork() } val secondJob = launch { doSomeMoreWork() } } } override fun onDestroy() { super.onDestroy() activityJob.cancel() } } bapspatil.com
  26. launch(context = coroutineContext) • Restricts the scope of the coroutine

    to Activity’s lifecycle. • Cancels all nested coroutines if parent coroutine is canceled. bapspatil.com
  27. CoroutineDispatcher 2+ 64+ Android Main Thread bapspatil.com • Dispatchers.Default •

    Dispatchers.IO • Dispatchers.Main • Dispatchers.Unconfined
  28. bapspatil.com suspend fun getFullMovieData(id: Int): Single<FullMovieData> { val movieData =

    moviesRepo.getMovieData(id).subscribeOn(Schedulers.io) val castData = moviesRepo.getCastData(id).subscribeOn(Schedulers.io) return Single.zip(movieData, castData, BiFunction { movieData, castData -> FullMovieData(movieData, castData) }) }
  29. bapspatil.com suspend fun getFullMovieData(id: Int): FullMovieData { id.let { val

    movieData = async { moviesRepo.getMovieData(it) } val castData = async { moviesRepo.getCastData(it) } return FullMovieData(movieData.await(), castData.await()) } return FullMovieData() }
  30. bapspatil.com suspend fun getMovieTitle(query: String?): Single<String> { return moviesRepo.searchForMovies(query).map {

    movieResults -> if(movieResults.isNotEmpty() && movieResults[0].title != null) { movieResults[0].title } else { errorString } } }
  31. bapspatil.com suspend fun getMovieTitle(query: String?): String? { query?.let { val

    movieResults = withContext(IO) { moviesRepo.searchForMovies(it) } val movieTitle = movieResults?.getOrNull(0)?.title return movieTitle ?: errorString } return “” }
  32. Thank you. linkedin.com/in/bapspatil medium.com/@bapspatil instagram.com/bapspatil twitter.com/baps_patil (couldn’t get @bapspatil for

    this one! ☹) Bapusaheb Patil Google Certified Android Developer • IDF Certified UX Designer www.bapspatil.com