$30 off During Our Annual Pro Sale. View Details »

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

    View Slide

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

    View Slide

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

    View Slide

  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)

    View Slide

  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ı

    View Slide

  6. Senaryo #1 Basit
    asenkron iş

    View Slide

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

    View Slide

  8. Coroutines

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  22. RxJava

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  27. RxJava Error
    Handling

    View Slide

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

    View Slide

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

    View Slide

  30. Coroutines Error
    Handling

    View Slide

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

    View Slide

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

    View Slide

  33. RxJava Android
    lifecycle

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  38. Coroutines Android
    lifecycle

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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ı

    View Slide

  45. RxJava Birleştirme
    operatörleri

    View Slide

  46. private fun readFileSingle(name: String): Single {
    return Single.create { singleEmitter ->
    singleEmitter.onSuccess(readFile(name))
    }.subscribeOn(Schedulers.io())
    }

    View Slide

  47. Single.zip(readFileSingle("thefile.txt")),
    readFileSingle(“theotherfile.txt")),
    BiFunction { 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)
    })

    View Slide

  48. Single.zip(readFileSingle("thefile.txt")),
    readFileSingle("theotherfile.txt")),
    BiFunction { 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)
    })

    View Slide

  49. Single.zip(readFileSingle("thefile.txt")),
    readFileSingle("theotherfile.txt")),
    BiFunction { 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)
    })

    View Slide

  50. Single.zip(readFileSingle("thefile.txt")),
    readFileSingle("theotherfile.txt")),
    BiFunction { 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)
    })

    View Slide

  51. Single.zip(readFileSingle("thefile.txt")),
    readFileSingle("theotherfile.txt")),
    BiFunction { 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)
    })

    View Slide

  52. coroutineScope

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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.

    View Slide

  58. RxJava ile asenkron
    api

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  66. Coroutines ile
    asenkron api

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  74. Senaryo #4 Streams
    ! RxJava BehaviorSubject, PublishSubject,
    ReplaySubject

    View Slide

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

    View Slide

  76. Senaryo #4 Streams
    ! RxJava BehaviorSubject, PublishSubject,
    ReplaySubject
    ! Channels
    ! Channels şu an deneysel

    View Slide

  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

    View Slide

  78. Teşekkürler
    sorular icin sliconf kodu rls6

    View Slide