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

Droid knights 2019 - Kotlin Corotuines

TaeHwan
April 05, 2019

Droid knights 2019 - Kotlin Corotuines

It deals with Kotlin coroutines.
CoroutineScope, GlobalScope, Android Lifecycle Following, Job, Poor Job, Good Job, supervisorScope, suspendCancellableCoroutine

TaeHwan

April 05, 2019
Tweet

More Decks by TaeHwan

Other Decks in Programming

Transcript

  1. • GDG Seoul ਍৔૓ • ٘۽੉٘ ա੉எ ਍৔૓ • ੹)

    ٧ܻߡܻ൤য۽௏ܻই উ٘۽੉٘ ѐߊ • അ) ஠஠য়ಕ੉ উ٘۽੉٘ ѐߊ • Blog : Է ݆਷ ѐߊ੗о غ੗! (https://thdev.tech) ࣗѐ
  2. $PSPVUJOF4DPQF $PSPVUJOFTDPEF @Test fun testCoroutines() = runBlocking { CoroutineScope(Dispatchers.Default) .launch

    { } delay(1500) } Hello println("Hello") delay(1000) println("droid knights!!!") Droid knights!!! delay 1 sec
  3. $PSPVUJOF4DPQF $PSPVUJOF4DPQFز੘ CoroutineScope(Dispatchers.IO).launch { val jobOne = launch { //

    jobOne } val jobTwo = launch { // jobTwo launch(Dispatchers.Main) { // jobTwo UI Thread } } jobOne.join() jobTwo.join() } jobOne jobTwo jobTwo(Main) jobOne / jobTwo زद प೯ Job two উীࢲ UI ୊ܻ CoroutineScope jobOne/jobTwo ઙܐ ؀ӝ
  4. $PSPVUJOF4DPQF (MPCBM4DPQF੉ۆ public object GlobalScope : CoroutineScope { /* *

    Returns [EmptyCoroutineContext]. */ override val coroutineContext: CoroutineContext get() = EmptyCoroutineContext } (MPCBM4DPQF੄*0 XPSLFS UISFBEীࢲز੘ 5ISFBE<%FGBVMU%JTQBUDIFSXPSLFS!DPSPVUJOF  NBJO>
  5. $PSPVUJOFT $PSPVUJOFTDPEF class MyActivity : AppCompatActivity(), CoroutineScope { // Jobਸ

    ١۾ೡ ࣻ ੓ب۾ ୡӝച private val job: Job = SupervisorJob() // ӝࠄ Main Thread ੿੄৬ jobਸ ೣԋ ୡӝച override val coroutineContext: CoroutineContext get() = Dispatchers.Main + job // ੘স ઺੉؍ ݽٚ jobਸ ઙ childrenਸ ઙܐ ୊ܻ override fun onDestroy() { super.onDestroy() job.cancel() // Cancel job on activity destroy. // After destroy all children jobs will be cancelled automatically } }
  6. +PC

  7. ↟+PC਷JOUFSGBDF۽੿੄غয੓׮ +PC $PSPVUJOFTKPC public interface Job : CoroutineContext.Element { //

    ... public val isActive: Boolean public val isCompleted: Boolean // ... }
  8. ↟+PC਷JOUFSGBDF۽੿੄غয੓׮ ↟MBVODI١ࢎਊदKPCё୓ܳSFUVSO // return jobਵ۽ ஶ౟܀ೞӝ val job = CoroutineScope(

    Dispatchers.Default).launch { // … } job.join() ↟߹ب੄KPCਸࢤࢿೡࣻ੓׮ val job = Job() CoroutineScope( Dispatchers.Default + job) .launch { } +PC $PSPVUJOFTKPC
  9. +PC ↟+PC਷JOUFSGBDF۽੿੄غয੓׮ ↟MBVODI١ࢎਊदKPCё୓ܳSFUVSO ↟߹ب੄KPCਸࢤࢿೡࣻ੓׮ ↟KPC੉ਊदDPSPVUJOF੄DBODFM TUBSU KPJO١ਸೡࣻ੓׮ ↟TUBSUDPSPVUJOFز੘࢚కഛੋ ↟USVFز੘઺ GBMTFળ࠺઺৮ܐ

    $PSPVUJOFTKPC ↟KPJODPSPVUJOF4DPQF੄ز੘ઙܐܳ؀ӝ ↟DBODFMDPSPVUJOF4DPQF੄ز੘ਸઙܐਬب ↟DBODFM"OE+PJODPSPVUJOF4DPQF੄ز੘ઙܐਃ୒ೞҊ ؀ӝ ↟DBODFM$IJMESFODPSPVUJOF4DPQF੄DIJMESFO੄ز੘ਸઙܐਬب
  10. +PC $PSPVUJOFTKPCTUBUVTଵҊਊद౟ State isActive isCompleted isCancelled New (optional initial state)

    FALSE FALSE FALSE Active (default initial state) TRUE FALSE FALSE Completing (transient state) TRUE FALSE FALSE Cancelling (transient state) FALSE FALSE TRUE Cancelled (final state) FALSE TRUE TRUE Completed (final state) FALSE TRUE FALSE
  11. @Test fun testCoroutines() = runBlocking { val job = Job()

    CoroutineScope(Dispatchers.Default + job).launch { CoroutineScope(Dispatchers.Default).launch { println("New CoroutineScope for start") for (index in 0..20) { if (isActive) { println("New CoroutineScope index $index") delay(1) } else { break } } println("New CoroutineScope for end") } val defaultJob = launch { println("Default for start") for (index in 0..10) { if (isActive) { println("Default index $index") +PC +PCੜޅࢎਊೠ৘DPEF
  12. @Test fun testCoroutines() = runBlocking { val job = Job()

    CoroutineScope(Dispatchers.Default + job).launch { CoroutineScope(Dispatchers.Default).launch { println("New CoroutineScope for start") for (index in 0..20) { if (isActive) { println("New CoroutineScope index $index") delay(1) } else { break } } println("New CoroutineScope for end") } val defaultJob = launch { println("Default for start") for (index in 0..10) { if (isActive) { println("Default index $index") +PC +PCੜޅࢎਊೠ৘DPEF Main CoroutineScope ୡӝച New CoroutineScope ୡӝച दীח job ನೣೞ૑ ঋ਺
  13. println("New CoroutineScope index $index") delay(1) } else { break }

    } println("New CoroutineScope for end") } val defaultJob = launch { println("Default for start") for (index in 0..10) { if (isActive) { println("Default index $index") delay(1) } else { break } } println("Default for end") } defaultJob.join() } job.cancel() delay(30) // 30ms test only. } +PC +PCੜޅࢎਊೠ৘DPEF Main CoroutinesCope਷ द੘җ زदী cancel ഐ୹ೠ׮
  14. @Test fun testCoroutines() = runBlocking { val job = Job()

    CoroutineScope(Dispatchers.Default + job).launch { CoroutineScope(Dispatchers.Default + job).launch { println("New CoroutineScope for start") for (index in 0..20) { if (isActive) { println("New CoroutineScope index $index") delay(1) } else { break } } println("New CoroutineScope for end") } val defaultJob = launch { println("Default for start") for (index in 0..10) { if (isActive) { println("Default index $index") delay(1) +PC ೧Ѿ New CoroutineScope ୡӝച दীب jobਸ ୶о
  15. +PC +PCਸખ؊࢓ಝࠁ੗ private val job = Job() private val coroutineScope

    = CoroutineScope(Dispatchers.IO + job) @Test fun testException() = runBlocking { with(coroutineScope) { println("Parent scope") val firstChildren = launch { println("First children is failing") throw Exception("First children is exception") } val secondChildren = launch { println("Second children is success") delay(500) println("Second children is delay 500ms") } firstChildren.join() secondChildren.join() } }
  16. +PC +PCਸખ؊࢓ಝࠁ੗ private val job = Job() private val coroutineScope

    = CoroutineScope(Dispatchers.IO + job) @Test fun testException() = runBlocking { with(coroutineScope) { println("Parent scope") val firstChildren = launch { println("First children is failing") } val secondChildren = launch { println("Second children is success") delay(500) println("Second children is delay 500ms") } firstChildren.join() secondChildren.join() } } Exception ъઁ ߊࢤ throw Exception("First children is exception")
  17. +PC 5IFNPTUCBTJDJOTUBODFTPG+PCBSFDSFBUFEXJUIMBVODIDPSPVUJOFCVJMEFSPSXJUIB+PC  GBDUPSZGVODUJPO#ZEFGBVMU BGBJMVSFPGBOZPGUIFKPCsTDIJMESFOMFBETUPBOJNNFEJBUFMZ GBJMVSFPGJUTQBSFOUBOEDBODFMMBUJPOPGUIFSFTUPGJUTDIJMESFO5IJTCFIBWJPSDBOCF DVTUPNJ[FEVTJOH4VQFSWJTPS+PC ޙࢲ۽ഛੋ೧ࠁ੗ #ZEFGBVMU BGBJMVSFPGBOZPGUIFKPCsTDIJMESFOMFBETUPBOJNNFEJBUFMZ

    GBJMVSFPGJUTQBSFOUBOEDBODFMMBUJPOPGUIFSFTUPGJUTDIJMESFO ޙࢲ : https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/ +PC ਷DIJMESFO઺ೞաоઙܐغݶ ࠗݽীѱా૑ೞҊ ࠗݽחݽٚDIJMESFOਸઙܐೞҊ ੗ӝب ઙܐೠ׮
  18. +PC ޙࢲܳӝ߈ਵ۽௏٘ܳ׮द࢓ಝࠁ੗ private val job = Job() private val coroutineScope

    = CoroutineScope(Dispatchers.IO + job) @Test fun testException() = runBlocking { with(coroutineScope) { println("Parent scope") val firstChildren = launch { println("First children is failing") throw Exception("First children is exception") } val secondChildren = launch { println("Second children is success") delay(500) println("Second children is delay 500ms") } firstChildren.join() secondChildren.join() } } Parent Scope਷ ׮ܲ childrenਸ ݽف ઙܐೞҊ, ੗ӝب ઙܐೠ׮. Exception ߊࢤ द ࠗݽীѱ ా૑
  19. +PC $PSPVUJOF4DPQ/ѐDIJMESFOਸо૕ࣻ੓׮ ੿ܻೞݶ Main CoroutineScope JobOne JobTwo … JobN 1ѐ੄

    children Exception ߊࢤ ݽٚ childrenҗ ࠗݽ ݽف ઙܐ ೞաۄبલਵݶࠗݽীѱా૑ೞҊݽفઙܐೠ׮
  20. Job() +PC 4VQFSWJTPS+PC੸ਊೞӝ private val job = private val coroutineScope

    = CoroutineScope(Dispatchers.IO + job) @Test fun testException() = runBlocking { with(coroutineScope) { println("Parent scope") val firstChildren = launch { println("First children is failing") throw Exception("First children is exception") } val secondChildren = launch { println("Second children is success") delay(500) println("Second children is delay 500ms") } firstChildren.join() secondChildren.join() } } SupervisorJob() private val coroutineScope = CoroutineScope(Dispatchers.IO + job) @Test fun testException() = runBlocking { with(coroutineScope) { println("Parent scope") val firstChildren = launch { println("First children is failing") throw Exception("First children is exception") } val secondChildren = launch { println("Second children is success") delay(500) println("Second children is delay 500ms") } firstChildren.join() secondChildren.join() } }
  21. public fun Job(parent: Job? = null): Job = JobImpl(parent) public

    fun SupervisorJob(parent: Job? = null) : Job = SupervisorJobImpl(parent) +PC +PCҗ4VQFSWJTPS+PCਸୡӝചೞח௏٘
  22. internal class JobImpl(parent: Job? = null) : JobSupport(true) { init

    { initParentJobInternal(parent) } override val cancelsParent: Boolean get() = true override val onCancelComplete get() = true override val handlesException: Boolean get() = false } +PC +PC*NQM4VQFSWJTPS+PC*NQM੄ҳഅ୓ܳࠁ੗ private class SupervisorJobImpl(parent: Job?) : JobSupport(true) { init { initParentJobInternal(parent) } override val cancelsParent: Boolean get() = true override val onCancelComplete get() = true override val handlesException: Boolean get() = false } override fun childCancelled(cause: Throwable): Boolean = false Child ஂࣗ ੿ࠁܳ parentীѱ ੹࣠ೡ૑ ৈࠗܳ Ѿ੿
  23. private fun cancelParent(cause: Throwable): Boolean { if (cause is CancellationException)

    return true if (!cancelsParent) return false return parentHandle?.childCancelled(cause) == true } +PC DIJME$BODFMMFEחয٣ࢲࠗܳө ৈӝীࢲ Ѿ੿ೞৈ ୊ܻೠ׮
  24. val errorHandler = CoroutineExceptionHandler { coroutineContext, exception -> 
 }

    &YDFQUJPO੉߮౟୊ܻ $PSPVUJOF&YDFQUJPO)BOEMFSࢎਊೞӝ // log to Crashlytics, logcat, etc.; can be dependency injected when (exception) { is NetworkErrorException -> { } is NetworkOnMainThreadException -> { } is CustomException -> { } else -> throw exception
 } ੿੄ೞ૑ ঋ਷ exception਷ Ӓ؀۽ ࠁղ੗
  25. val errorHandler = CoroutineExceptionHandler { coroutineContext, exception -> // log

    to Crashlytics, logcat, etc.; can be dependency injected } &YDFQUJPO੉߮౟୊ܻ $PSPVUJOF&YDFQUJPO)BOEMFSࢎਊೞӝ private val job = SupervisorJob() private val coroutineScope = CoroutineScope(job + Dispatchers.Default + errorHandler) launch(errorHandler)
  26. public suspend fun supervisorScope(block: suspend CoroutineScope.() -> ): = block:

    suspend CoroutineScope.() -> ژ׮ܲয়ܨ୊ܻ TVQFSWJTPS4DPQF suspendCoroutineUninterceptedOrReturn { uCont -> val coroutine = SupervisorCoroutine(uCont.context, uCont) coroutine.startUndispatchedOrReturn(coroutine, block) } <R> R R
  27. @Test fun testException() = runBlocking { with(coroutineScope) println("Parent scope") val

    firstChildren = launch { println("First children is failing") throw Exception("First children is exception") } val secondChildren = launch { println("Second children is success") delay(500) println("Second children is delay 500ms") } firstChildren.join() secondChildren.join() } } with(coroutineScope) { ژ׮ܲয়ܨ୊ܻ TVQFSWJTPS4DPQFࢎਊ਷ supervisorScope {
  28. ژ׮ܲয়ܨ୊ܻ TVQFSWJTPS4DPQFࢎਊ਷ 1BSFOUTDPQF 'JSTUDIJMESFOJTGBJMJOH j 4FDPOEDIJMESFOJTTVDDFTT j   

     4FDPOEDIJMESFOJTEFMBZNT  BUPSHKVOJUSVOOFST#MPDL+6OJU$MBTT3VOOFSSVO$IJME #MPDL+6OJU$MBTT3VOOFSKBWB   BUDPNJOUFMMJKSUFYFDVUJPOKVOJU+6OJU4UBSUFSNBJO +6OJU4UBSUFSKBWB &YDFQUJPOJOUISFBENBJO!DPSPVUJOFKBWBMBOH&YDFQUJPO'JSTUDIJMESFOJTFYDFQUJPOBU UFDIUIEFWDPSPVUJOFTTDPQF6*$PSPVUJOF4DPQF5FTUUFTU&YDFQUJPOGJSTU$IJMESFOJOWPLF4VTQF OE 6*$PSPVUJOF4DPQF5FTULU
  29. private class SupervisorCoroutine<R>( parentContext: CoroutineContext, @JvmField val uCont: Continuation<R> )

    : AbstractCoroutine<R>(parentContext, true) { override val defaultResumeMode: Int get() = MODE_DIRECT @Suppress("UNCHECKED_CAST") internal override fun onCompletionInternal(state: Any?, mode: Int, suppressed: Boolean) { if (state is CompletedExceptionally) uCont.resumeUninterceptedWithExceptionMode(state.cause, mode) else uCont.resumeUninterceptedMode(state as R, mode) } } ژ׮ܲয়ܨ୊ܻ TVQFSWJTPS4DPQF੄DIJME$BODFMMFE୊ܻ override fun childCancelled(cause: Throwable): Boolean = false
  30. ೞա؊ 4VTQFOETDPSPVUJOFTJNJMBSUPTVTQFOE$PSPVUJOF CVUQSPWJEFBOJNQMFNFOUBUJPOPG $BODFMMBCMF$POUJOVBUJPOUPUIFCMPDL5IJTGVODUJPOUISPXT$BODFMMBUJPO&YDFQUJPOJGUIF DPSPVUJOFJTDBODFMMFEPSDPNQMFUFEXIJMFTVTQFOEFE TVTQFOE$BODFMMBCMF$PSPVUJOF ޙࢲ : https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/suspend-cancellable-coroutine.html TVTQFOE$PSPVUJOFҗਬࢎ

    $PSPVUJOFੌद઺૑ژחஂࣗद$BODFMMBUJPO&YDFQUJPOਸੌਵఅ׮ TJNJMBSUPTVTQFOE$PSPVUJOF $BODFMMBUJPO&YDFQUJPOJGUIF DPSPVUJOFJTDBODFMMFEPSDPNQMFUFEXIJMFTVTQFOEFE
  31. public suspend fun <T : Any> Call<T>.await(): T { return

    enqueue(object : Callback<T> { override fun onResponse(call: Call<T>?, response: Response<T?>) { if (response.isSuccessful) { response.body() ?: throw NullPointerException("Response body is null: $response") } else { throw HttpException(response) } }) } override fun onFailure(call: Call<T>, t: Throwable) { if (continuation.isCancelled) return } }) } } ೞա؊ 3FUSPGJUTVTQFOE$BODFMMBCMF$PSPVUJOF 3FUSPGJUIUUQTLPUMJOHJUIVCJPLPUMJOYDPSPVUJOFTLPUMJOYDPSPVUJOFTDPSFLPUMJOYDPSPVUJOFTDPSPVUJOFFYDFQUJPOIBOEMFS suspendCancellableCoroutine { continuation -> continuation.resumeWith(runCatching { continuation.resumeWithException(t) registerOnCompletion(continuation)
  32. private fun Call<*>.registerOnCompletion(continuation: CancellableContinuation<*>) { continuation.invokeOnCancellation { try { cancel()

    } catch (ex: Throwable) { //Ignore cancel exception } } } ೞա؊ 3FUSPGJUTVTQFOE$BODFMMBCMF$PSPVUJOF 3FUSPGJUIUUQTLPUMJOHJUIVCJPLPUMJOYDPSPVUJOFTLPUMJOYDPSPVUJOFTDPSFLPUMJOYDPSPVUJOFTDPSPVUJOFFYDFQUJPOIBOEMFS
  33. ஠஠য়ಕ੉ ௿ۄ੉঱౟(Android) ѐߊ੗ ৔ੑ ૣ਷ दр ੉ܘ ࢿҗࠁ׮ ؊ ষ୒աҊ

    ֥ۄ਍ ࣁ࢚ਸ ஠஠য়ಕ੉৬ ೣԋ ৌযт, ߄۽ ׼नਸ ӝ׮݀פ׮! ૑ਗೞӝ ◆ ૑ਗ੗Ѻ - ׮নೠ UI ѐߊ ҃೷җ ࢎਊ੗ ҃೷ী ؀ೠ Ө਷ ੉೧ - য়೑ࣗझী Ѣࠗх੉ হҊ ੉೧بо ֫਷ ࠙ - ֤ܻ੸੉Ҋ ୓҅੸ੋ ޙઁ೧Ѿ מ۱ - ബҗ੸ੋ ੄ࢎ੹׳, ࢚؀ߑਸ ҃୒ೞח ழޭפா੉࣌ מ۱