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

Kotlin Coroutines: Let it async in • Bapusaheb ...

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.

Avatar for Bapusaheb Patil

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