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

RxJava vs Coroutines

A6c0dcba5f373b33df2c2c55540faab1?s=47 Hadi Tok
November 04, 2018

RxJava vs Coroutines

A6c0dcba5f373b33df2c2c55540faab1?s=128

Hadi Tok

November 04, 2018
Tweet

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