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

RxJava vs Coroutines

Hadi Tok
November 04, 2018

RxJava vs Coroutines

Hadi Tok

November 04, 2018
Tweet

More Decks by Hadi Tok

Other Decks in Programming

Transcript

  1. Kotlin Coroutines ve RxJava kullanım senaryoları Hadi Tok Lead Android

    Dev @CitizenMe
  2. Data layer Business Logic Layer UI Layer Observable (Single, Completable,

    Maybe) I/O (Network-File-DB)
  3. Data layer Business Logic Layer UI Layer Observable (Single, Completable,

    Maybe) Observable (Single, Completable, Maybe) I/O (Network-File-DB)
  4. Data layer Business Logic Layer UI Layer Observable (Single, Completable,

    Maybe) Observable (Single, Completable, Maybe) Observable (Single, Completable, Maybe) I/O (Network-File-DB)
  5. Coroutines ! Kod akışının belirli bir noktada duraklatılıp paraleldeki başka

    bir işin tamamlanmasından sonra devam edebilmesi ! Hafif siklet (lightweight) thread ! Geçtiğimiz hafta stable release olarak yayınlandı
  6. Senaryo #1 Basit asenkron iş

  7. private fun readFile(name: String): String { return assets.open(name).bufferedReader().use { it.readText()

    } }
  8. Coroutines

  9. GlobalScope.launch(Dispatchers.Main) { textView.text = readFile("thefile.txt") }

  10. GlobalScope.launch(Dispatchers.Main) { textView.text = readFile("thefile.txt") }

  11. GlobalScope.launch(Dispatchers.Main) { textView.text = readFile("thefile.txt") }

  12. GlobalScope.launch(Dispatchers.Main) { textView.text = readFile("thefile.txt") }

  13. GlobalScope.launch(Dispatchers.Main) { textView.text = readFile("thefile.txt") }

  14. GlobalScope.launch(Dispatchers.Main) { textView.text = readFile("thefile.txt") }

  15. GlobalScope.launch(Dispatchers.Main) { textView.text = async(Dispatchers.IO) { readFile(“thefile.txt") }.await() }

  16. GlobalScope.launch(Dispatchers.Main) { val deferred: Deferred<String> = async(Dispatchers.IO) { readFile("thefile.txt") }

    val string: String = deferred.await() textView.text = string }
  17. GlobalScope.launch(Dispatchers.Main) { val deferred: Deferred<String> = async(Dispatchers.IO) { readFile("thefile.txt") }

    val string: String = deferred.await() textView.text = string }
  18. GlobalScope.launch(Dispatchers.Main) { val deferred: Deferred<String> = async(Dispatchers.IO) { readFile("thefile.txt") }

    val string: String = deferred.await() textView.text = string }
  19. GlobalScope.launch(Dispatchers.Main) { val deferred: Deferred<String> = async(Dispatchers.IO) { readFile("thefile.txt") }

    val string: String = deferred.await() textView.text = string }
  20. GlobalScope.launch(Dispatchers.Main) { val deferred: Deferred<String> = async(Dispatchers.IO) { readFile("thefile.txt") }

    val string: String = deferred.await() textView.text = string }
  21. GlobalScope.launch(Dispatchers.Main) { val deferred: Deferred<String> = async(Dispatchers.IO) { readFile("thefile.txt") }

    val string: String = deferred.await() textView.text = string }
  22. RxJava

  23. Single.create<String> { singleEmitter -> val string = readFile("thefile.txt") singleEmitter.onSuccess(string)) }.subscribeOn(Schedulers.io())

    .observeOn(AndroidSchedulers.mainThread()) .subscribe { string -> textView.text = string }
  24. Single.create<String> { singleEmitter -> val string = readFile("thefile.txt") singleEmitter.onSuccess(string)) }.subscribeOn(Schedulers.io())

    .observeOn(AndroidSchedulers.mainThread()) .subscribe { string -> textView.text = string }
  25. Single.create<String> { singleEmitter -> val string = readFile("thefile.txt") singleEmitter.onSuccess(string)) }.subscribeOn(Schedulers.io())

    .observeOn(AndroidSchedulers.mainThread()) .subscribe { string -> textView.text = string }
  26. Single.create<String> { singleEmitter -> singleEmitter.onSuccess(readFile("thefile.txt"))) }.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { string

    -> textView.text = string }
  27. RxJava Error Handling

  28. Single.create<String> { singleEmitter -> singleEmitter.onSuccess(readFile("thefile.txt"))) }.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ string ->

    textView.text = string }, { e -> if (e is IOException) { handleIOException(e) } })
  29. Single.create<String> { singleEmitter -> singleEmitter.onSuccess(readFile("thefile.txt"))) }.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ string ->

    textView.text = string }, { e -> if (e is IOException) { handleIOException(e) } })
  30. Coroutines Error Handling

  31. GlobalScope.launch(Dispatchers.Main) { try { textView.text = async(Dispatchers.IO) { readFile("thefile.txt") }.await()

    } catch (e: IOException) { handleIOException(e) } }
  32. GlobalScope.launch(Dispatchers.Main) { try { textView.text = async(Dispatchers.IO) { readFile("thefile.txt") }.await()

    } catch (e: IOException) { handleIOException(e) } }
  33. RxJava Android lifecycle

  34. val disposable = Single.create<String> {…} .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({…}, {…}) compositeDisposable.add(disposable)

    override fun onDestroy() { super.onDestroy() compositeDisposable.dispose() }
  35. val disposable = Single.create<String> {…} .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({…}, {…}) compositeDisposable.add(disposable)

    override fun onDestroy() { super.onDestroy() compositeDisposable.dispose() }
  36. val disposable = Single.create<String> {…} .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({…}, {…}) compositeDisposable.add(disposable)

    override fun onDestroy() { super.onDestroy() compositeDisposable.dispose() }
  37. val disposable = Single.create<String> {…} .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({…}, {…}) compositeDisposable.add(disposable)

    override fun onDestroy() { super.onDestroy() compositeDisposable.dispose() }
  38. Coroutines Android lifecycle

  39. class MainActivity : AppCompatActivity() , CoroutineScope { private lateinit var

    job: Job override val coroutineContext: CoroutineContext get() = Dispatchers.Main + job override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) job = Job() } override fun onDestroy() { super.onDestroy() job.cancel() } }
  40. class MainActivity : AppCompatActivity() , CoroutineScope { private lateinit var

    job: Job override val coroutineContext: CoroutineContext get() = Dispatchers.Main + job override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) job = Job() } override fun onDestroy() { super.onDestroy() job.cancel() } }
  41. class MainActivity : AppCompatActivity() , CoroutineScope { private lateinit var

    job: Job override val coroutineContext: CoroutineContext get() = Dispatchers.Main + job override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) job = Job() } override fun onDestroy() { super.onDestroy() job.cancel() } }
  42. GlobalScope.launch(Dispatchers.Main) { try { textView.text = async(Dispatchers.IO) { readFile("thefile.txt") }.await()

    } catch (e: IOException) { handleIOException(e) } }
  43. launch{ try { textView.text = async(Dispatchers.IO) { readFile("thefile.txt") }.await() }

    catch (e: IOException) { handleIOException(e) } }
  44. Senaryo #2 iki asenkron işin sonuçlarını birleştirme ! Paralelde çalışan

    iki iş ! Sonuçları birbirine bağımlı ! Sonuç başarılı ya da başarısız tek bir yerde toplanmalı
  45. RxJava Birleştirme operatörleri

  46. private fun readFileSingle(name: String): Single<String> { return Single.create<String> { singleEmitter

    -> singleEmitter.onSuccess(readFile(name)) }.subscribeOn(Schedulers.io()) }
  47. Single.zip(readFileSingle("thefile.txt")), readFileSingle(“theotherfile.txt")), BiFunction<String, String, String> { t1, t2 -> "$t1

    \n$t2" }).observeOn(AndroidSchedulers.mainThread()) .subscribe({ textView.text = it }, { e -> if (e is IOException) { handleIOException(e) } Log.e(TAG,e.message,e) })
  48. Single.zip(readFileSingle("thefile.txt")), readFileSingle("theotherfile.txt")), BiFunction<String, String, String> { t1, t2 -> "$t1

    \n$t2" }).observeOn(AndroidSchedulers.mainThread()) .subscribe({ textView.text = it }, { e -> if (e is IOException) { handleIOException(e) } Log.e(TAG,e.message,e) })
  49. Single.zip(readFileSingle("thefile.txt")), readFileSingle("theotherfile.txt")), BiFunction<String, String, String> { t1, t2 -> "$t1

    \n$t2" }).observeOn(AndroidSchedulers.mainThread()) .subscribe({ textView.text = it }, { e -> if (e is IOException) { handleIOException(e) } Log.e(TAG,e.message,e) })
  50. Single.zip(readFileSingle("thefile.txt")), readFileSingle("theotherfile.txt")), BiFunction<String, String, String> { t1, t2 -> "$t1

    \n$t2" }).observeOn(AndroidSchedulers.mainThread()) .subscribe({ textView.text = it }, { e -> if (e is IOException) { handleIOException(e) } Log.e(TAG,e.message,e) })
  51. Single.zip(readFileSingle("thefile.txt")), readFileSingle("theotherfile.txt")), BiFunction<String, String, String> { t1, t2 -> "$t1

    \n$t2" }).observeOn(AndroidSchedulers.mainThread()) .subscribe({ textView.text = it }, { e -> if (e is IOException) { handleIOException(e) } Log.e(TAG,e.message,e) })
  52. coroutineScope

  53. private fun readFileDeferred(name: String) = async(Dispatchers.IO) { readFile(name) }

  54. launch(Dispatchers.Main) { try { coroutineScope { val s1 = readFileDeferred("thefile.txt").await()

    val s2 = readFileDeferred("theotherfile.txt").await() textView.text = "$s1 \n$s2" } } catch (e: IOException) { handleIOException(e) } }
  55. launch(Dispatchers.Main) { try { coroutineScope { val s1 = readFileDeferred("thefile.txt").await()

    val s2 = readFileDeferred("theotherfile.txt").await() textView.text = "$s1 \n$s2" } } catch (e: IOException) { handleIOException(e) } }
  56. launch(Dispatchers.Main) { try { coroutineScope { val s1 = readFileDeferred("thefile.txt").await()

    val s2 = readFileDeferred("theotherfile.txt").await() textView.text = "$s1 \n$s2" } } catch (e: IOException) { handleIOException(e) } }
  57. Senaryo #3 Asenkron bir api’yi kullanma ! Callback ile çalışan

    bir api’ı belirli bir flowun içerisine katmak istiyoruz ! Elimizde halihazırda bir sonuç varsa sonucu dönüp sonuç yoksa apiden gelecek sonucu döndürmek istiyoruz. ! Kodlama stilinin proje geneli ile aynı olmasını istiyoruz.
  58. RxJava ile asenkron api

  59. private fun getAppFolder(): Single<DriveFolder> { return Single.create<DriveFolder> { emitter ->

    if (folder != null) { emitter.onSuccess(folder !!) } else { getDriveResourceClient().appFolder .addOnSuccessListener { appFolder -> folder = appFolder emitter.onSuccess(appFolder) }.addOnFailureListener { emitter.onError(it) } } } }
  60. private fun getAppFolder(): Single<DriveFolder> { return Single.create<DriveFolder> { emitter ->

    if (folder != null) { emitter.onSuccess(folder !!) } else { getDriveResourceClient().appFolder .addOnSuccessListener { appFolder -> folder = appFolder emitter.onSuccess(appFolder) }.addOnFailureListener { emitter.onError(it) } } } }
  61. private fun getAppFolder(): Single<DriveFolder> { return Single.create<DriveFolder> { emitter ->

    if (folder != null) { emitter.onSuccess(folder !!) } else { getDriveResourceClient().appFolder .addOnSuccessListener { appFolder -> folder = appFolder emitter.onSuccess(appFolder) }.addOnFailureListener { emitter.onError(it) } } } }
  62. private fun getAppFolder(): Single<DriveFolder> { return Single.create<DriveFolder> { emitter ->

    if (folder != null) { emitter.onSuccess(folder !!) } else { getDriveResourceClient().appFolder .addOnSuccessListener { appFolder -> folder = appFolder emitter.onSuccess(appFolder) }.addOnFailureListener { emitter.onError(it) } } } }
  63. private fun getAppFolder(): Single<DriveFolder> { return Single.create<DriveFolder> { emitter ->

    if (folder != null) { emitter.onSuccess(folder !!) } else { getDriveResourceClient().appFolder .addOnSuccessListener { appFolder -> folder = appFolder emitter.onSuccess(appFolder) }.addOnFailureListener { emitter.onError(it) } } } }
  64. private fun getAppFolder(): Single<DriveFolder> { return Single.create<DriveFolder> { emitter ->

    if (folder != null) { emitter.onSuccess(folder !!) } else { getDriveResourceClient().appFolder .addOnSuccessListener { appFolder -> folder = appFolder emitter.onSuccess(appFolder) }.addOnFailureListener { emitter.onError(it) } } } }
  65. getAppFolder().subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ appFolder -> Toast.makeText(this, "AppFolder id'si = ${appFolder.driveId

    ?.resourceId}", Toast.LENGTH_LONG).show() }, { Toast.makeText(this, "Bir hata oluştu", Toast.LENGTH_LONG).show() })
  66. Coroutines ile asenkron api

  67. private suspend fun getAppFolder() = suspendCoroutine<DriveFolder>{continuation -> if (folder !=

    null) { continuation.resume(folder !!) } else { getDriveResourceClient().appFolder .addOnSuccessListener { appFolder -> folder = appFolder continuation.resume(appFolder) }.addOnFailureListener { continuation.resumeWithException(it) } } }
  68. private suspend fun getAppFolder() = suspendCoroutine<DriveFolder>{continuation -> if (folder !=

    null) { continuation.resume(folder !!) } else { getDriveResourceClient().appFolder .addOnSuccessListener { appFolder -> folder = appFolder continuation.resume(appFolder) }.addOnFailureListener { continuation.resumeWithException(it) } } }
  69. private suspend fun getAppFolder() = suspendCoroutine<DriveFolder>{continuation -> if (folder !=

    null) { continuation.resume(folder !!) } else { getDriveResourceClient().appFolder .addOnSuccessListener { appFolder -> folder = appFolder continuation.resume(appFolder) }.addOnFailureListener { continuation.resumeWithException(it) } } }
  70. private suspend fun getAppFolder() = suspendCoroutine<DriveFolder>{continuation -> if (folder !=

    null) { continuation.resume(folder !!) } else { getDriveResourceClient().appFolder .addOnSuccessListener { appFolder -> folder = appFolder continuation.resume(appFolder) }.addOnFailureListener { continuation.resumeWithException(it) } } }
  71. private suspend fun getAppFolder() = suspendCoroutine<DriveFolder>{continuation -> if (folder !=

    null) { continuation.resume(folder !!) } else { getDriveResourceClient().appFolder .addOnSuccessListener { appFolder -> folder = appFolder continuation.resume(appFolder) }.addOnFailureListener { continuation.resumeWithException(it) } } }
  72. private suspend fun getAppFolder() = suspendCoroutine<DriveFolder>{continuation -> if (folder !=

    null) { continuation.resume(folder !!) } else { getDriveResourceClient().appFolder .addOnSuccessListener { appFolder -> folder = appFolder continuation.resume(appFolder) }.addOnFailureListener { continuation.resumeWithException(it) } } }
  73. launch { try { val appFolder = async(Dispatchers.IO) { getAppFolder()

    }.await() Toast.makeText(this@MainActivity, "AppFolder id'si = ${appFolder.driveId ?.resourceId}", Toast.LENGTH_LONG).show() } catch (e: Exception) { Toast.makeText(this@MainActivity, "Bir hata oluştu", Toast.LENGTH_LONG).show() } }
  74. Senaryo #4 Streams ! RxJava BehaviorSubject, PublishSubject, ReplaySubject

  75. Senaryo #4 Streams ! RxJava BehaviorSubject, PublishSubject, ReplaySubject ! Channels

  76. Senaryo #4 Streams ! RxJava BehaviorSubject, PublishSubject, ReplaySubject ! Channels

    ! Channels şu an deneysel
  77. Kaynaklar ! Coroutines guide: https://github.com/Kotlin/ kotlinx.coroutines/blob/master/docs/coroutines- guide.md ! Roman Elizarov

    Medium: https://medium.com/ @elizarov ! kotlinlang.slack.com #coroutines
  78. Teşekkürler sorular icin sliconf kodu rls6