Slide 1

Slide 1 text

Kotlin Coroutines ve RxJava kullanım senaryoları Hadi Tok Lead Android Dev @CitizenMe

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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ı

Slide 6

Slide 6 text

Senaryo #1 Basit asenkron iş

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

Coroutines

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

RxJava

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

RxJava Error Handling

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

Coroutines Error Handling

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

RxJava Android lifecycle

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Coroutines Android lifecycle

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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ı

Slide 45

Slide 45 text

RxJava Birleştirme operatörleri

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

coroutineScope

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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.

Slide 58

Slide 58 text

RxJava ile asenkron api

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

Coroutines ile asenkron api

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

Senaryo #4 Streams ! RxJava BehaviorSubject, PublishSubject, ReplaySubject

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

Teşekkürler sorular icin sliconf kodu rls6