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

Androidの非同期処理をKotlinコルーチンで行う

800912a73ce4e879003b6c89cf80cfeb?s=47 yagi
June 12, 2017

 Androidの非同期処理をKotlinコルーチンで行う

800912a73ce4e879003b6c89cf80cfeb?s=128

yagi

June 12, 2017
Tweet

Transcript

  1. "OESPJEͷඇಉظॲཧΛ ɹɹɹɹɹίϧʔνϯͰߦ͏ 3Y+B/JHIU 5PTIJIJSP:BHJ

  2. ࣗݾ঺հ w ീ໦ढ़޿ !TZTZBHJ  w "OESPJEΤϯδχΞ ٕज़෦௕

  3. 3Y+B/JHIUͳͷʹ ίϧʔνϯʁ

  4. 3Y+BWBͷ༻్ w -JTUॲཧͷந৅ԽɾετϦʔϜԽ w 0QUJPOBM w 1SPNJTF w %BUB#JOEJOH w

    &WFOU#VT
  5. 3Y+BWBͷ༻్ w -JTUॲཧͷந৅ԽɾετϦʔϜԽ w 0QUJPOBM w 1SPNJTF w %BUB#JOEJOH w

    &WFOU#VT
  6. 1SPNJTFͱͯ͠ͷ3Y+BWBΛ ίϧʔνϯ BTZODBXBJU  Ͱஔ͖׵͑ΒΕΔͷͰ͸ʁ

  7. ΞδΣϯμ w ίϧʔνϯͱ͸ͳʹ͔ w ,PUMJOʹ͓͚Δίϧʔνϯ w ࠓճऔΓѻ͏ඇಉظॲཧͷൣғ w 3Y+BWBͰͷ࣮૷ w

    ίϧʔνϯͰͷ࣮૷ w ײ૝
  8. ίϧʔνϯͱ͸ͳʹ͔

  9. ίϧʔνϯͱ͸ͳʹ͔ w ίϧʔνϯʢӳDPSPVUJOFʣͱ͸ϓϩάϥϛ ϯάͷߏ଄ͷҰछɻαϒϧʔνϯ͕ΤϯτϦʔ͔ ΒϦλʔϯ·ͰΛҰͭͷॲཧ୯Ґͱ͢Δͷʹର͠ɺ ίϧʔνϯ͸͍ͬͨΜॲཧΛதஅͨ͠ޙɺଓ͖͔ ΒॲཧΛ࠶։Ͱ͖Δ w αϒϧʔνϯͱҟͳΓɺঢ়ଶ؅ཧΛҙࣝͤͣʹߦ ͑ΔͨΊɺڠௐతॲཧɺΠςϨʔλɺແݶϦετɺ

    ύΠϓͳͲɺܧଓঢ়گΛ࣋ͭϓϩάϥϜ͕༰қʹ هड़Ͱ͖Δɻ WJB8JLJQFEJBIUUQTKBXJLJQFEJBPSHXJLJ&#&"#&#$&&#
  10. ؔ਺ͷ్தͰதஅͨ͠Γ ࠶։ͨ͠ΓͰ͖Δ΍ͭ

  11. ,PUMJOʹ͓͚Δίϧʔνϯ

  12. ,PUMJO͔Βಋೖ w ʹϦϦʔε w ݴޠ࢓༷ʹʮίϧʔνϯΛ࣮૷͢ΔͨΊ ͷػೳʯΛ௥Ճ ࢓༷Λٞ࿦͢ΔϦϙδτϦ IUUQTHJUIVCDPN,PUMJOLPUMJODPSPVUJOFTCMPCNBTUFSLPUMJODPSPVUJOFTJOGPSNBMNE

  13. ࣮ࡍͷػೳ͸ϥΠϒϥϦͱͯ͠ఏڙ w DPSF SFBDUJWF VJ JOUFHSBUJPOͳ ͲͷϞδϡʔϧʹ෼͔Ε͍ͯΔ ίϧʔνϯϥΠϒϥϦͷϦϙδτϦ IUUQTHJUIVCDPN,PUMJOLPUMJOYDPSPVUJOFT

  14. "OESPJE޲͚ʹ΋ଗ͍ͬͯΔ w DPSFͱVJBOESPJEϞδϡʔϧΛ࢖͑͹ େମ͍͚Δ "OESPJEϞδϡʔϧͷ༷ࢠ IUUQTHJUIVCDPN,PUMJOLPUMJOYDPSPVUJOFTUSFFNBTUFSVJLPUMJOYDPSPVUJOFTBOESPJE

  15. ͨͩ͠·ͩFYQFSJNFOUBM w LPUMJOYDPSPVUJOFTFYQFSJNFOUBM ύοέʔδʹؔ࿈͢ΔΫϥε͕͋Δ w ຊ൪౤ೖ͸ͦΕͳΓʹ֮ޛ͕ඞཁ

  16. ࠓճऔΓѻ͏ඇಉظॲཧͷൣғ

  17. ࠓճऔΓѻ͏ඇಉظॲཧͷൣғ w ୯ൃͷ࣮ߦ w ௚ྻͷ࣮ߦ w ฒྻͷ࣮ߦ w ΤϥʔϋϯυϦϯά w

    Ωϟϯηϧ ʴ
  18. 3Y+BWBͰͷ࣮૷

  19. ؀ڥ w 3Y"OESPJE w 3Y,PUMJO

  20. ୯ൃͷ࣮ߦ val disposable = shopApi.getShop(10) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( { //

    success }, { // error } ) εέδϡʔϥΛ͍͍ײ͡ʹઃఆ
  21. ௚ྻͷ࣮ߦ val disposable = userApi.me() .flatMap { user -> subscriptionShopApi.getSubscriptionShops(user.id)

    } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( { // success }, { // error } ) qBU.BQΛ࢖ͬͯ௚ྻʹ࣮ߦ͢Δ
  22. ฒྻͷ࣮ߦ val disposable = Single.zip<User, Shop, Pair<User, Shop>>( userApi.me().subscribeOn(Schedulers.io()), shopApi.getShop(10L).subscribeOn(Schedulers.io()),

    BiFunction { user, shop -> Pair(user, shop) } ) .observeOn(AndroidSchedulers.mainThread()) .subscribe( { (user, shop) -> // success }, { // error } ) [JQΛ࢖ͬͯฒྻʹ࣮ߦ͢Δ
  23. Ωϟϯηϧ val disposable = shopApi.getShop(10) .subscribe(/*ུ*/) disposable.dispose()

  24. ίϧʔνϯͰͷ࣮૷

  25. ؀ڥ w ,PUMJO w LPUMJOYDPSPVUJOFTDPSF w LPUMJOYDPSPVUJOFTBOESPJE

  26. ୯ൃͷ࣮ߦ val job = launch(UI) { try { val shop

    = async(CommonPool) { shopApi.getShop(10) }.await() // success! } catch (e: Exception) { // error } }
  27. ୯ൃͷ࣮ߦ val job = launch(UI) { try { val shop

    = async(CommonPool) { shopApi.getShop(10) }.await() // success! } catch (e: Exception) { // error } } Ϗϧμʔؔ਺ͱΑ͹ΕΔɺ ίϧʔνϯΛߏங͢Δؔ਺
  28. MBVODIؔ਺ w $PSPVUJOF$POUFYUʹ࣮ߦ؀ڥΛࢦఆ͢Δ w $PSPVUJOF4UBSU͸࣮ߦ։࢝ͷλΠϛϯάΛࢦఆ͢Δ w ୈࡾҾ਺ʹ࣮ߦ͢ΔϒϩοΫΛ౉͢ w ࣮ߦঢ়ଶΛද͢+PCΛฦ͢ IUUQTLPUMJOHJUIVCJPLPUMJOYDPSPVUJOFTLPUMJOYDPSPVUJOFTDPSFLPUMJOYDPSPVUJOFTFYQFSJNFOUBMMBVODIIUNM

    fun launch( context: CoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job
  29. MBVODIؔ਺ val job = launch(UI) { //…

  30. MBVODIؔ਺ val job = launch(UI) { //… LPUMJOYDPSPVUJOFTBOESPJE͕ఏڙ͢Δ$PSPVUJOF$POUFYUɻ ౉ͨ͠ϒϩοΫ಺ͷ͢΂ͯͷ࠶։ॲཧΛ6*εϨουͰߦ͏ɻ

  31. BTZODؔ਺ w ୈࡾҾ਺Ͱ࣮ߦ͢ΔϒϩοΫ͕໭Γ஋Λ࣋ͭ w ࣮ߦঢ়ଶͱ࣮ߦ݁ՌΛ࣋ͭ%FGFSSFE5Λฦ͢ IUUQTLPUMJOHJUIVCJPLPUMJOYDPSPVUJOFTLPUMJOYDPSPVUJOFTDPSFLPUMJOYDPSPVUJOFTFYQFSJNFOUBMBTZODIUNM fun <T> async( context:

    CoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T ): Deferred<T>
  32. BTZODؔ਺ val job = launch(UI) { try { val shop

    = async(CommonPool) { shopApi.getShop(10) }.await() //…
  33. BTZODؔ਺ val job = launch(UI) { try { val shop

    = async(CommonPool) { shopApi.getShop(10) }.await() //… LPUMJOYDPSPVUJOFTDPSF͕ఏڙ͢Δ$PSPVUJOF$POUFYUɻ KBWBVUJMDPODVSSFOU'PSL+PJO1PPMDPNNPO1PPM Λ ࢖ͬͯεϨουϓʔϧΛ࡞Γɺ࠶։ॲཧΛεϨουͰ࣮ߦ͢Δɻ "OESPJE؀ڥ /FYVT9 Ͱ͸ϓʔϧαΠζ͸ͩͬͨɻ
  34. ୯ൃͷ࣮ߦ val job = launch(UI) { try { val shop

    = async(CommonPool) { shopApi.getShop(10) }.await() // success! } catch (e: Exception) { // error } }
  35. ୯ൃͷ࣮ߦ val job = launch(UI) { try { val shop

    = async(CommonPool) { shopApi.getShop(10) }.await() // success! } catch (e: Exception) { // error } } 6*εϨουͰ଴ͪ߹Θ͍͍ͤͯͷ͔ͳʜ
  36. ୯ൃͷ࣮ߦ val job = launch(UI) { try { val shop

    = async(CommonPool) { shopApi.getShop(10) }.await() // success! } catch (e: Exception) { // error } } %FGFSSFEBXBJU ͸தஅؔ਺
  37. தஅؔ਺ͱεςʔτϚγϯ w ίϯύΠϥ͕தஅؔ਺ͷݺͼग़͠Λঢ়ଶͱͯ͠෼ ղ͠ɺॲཧશମΛεςʔτϚγϯʹม׵͢Δɻ͜ ΕʹΑΓɺؔ਺ͷதஅͱ࠶։Λ࣮ݱ͍ͯ͠Δ launch(UI) { try { val

    shop = async(CommonPool) {…}.await() // success! } catch (e: Exception) { // error } } ঢ়ଶ async(CommonPool){…}.await() ঢ়ଶ val shop =… success ঢ়ଶ error
  38. ୯ൃͷ࣮ߦ val job = launch(UI) { try { val shop

    = async(CommonPool) { shopApi.getShop(10) }.await() // success! } catch (e: Exception) { // error } }
  39. ୯ൃͷ࣮ߦ val job = launch(UI) { try { val shop

    = async(CommonPool) { shopApi.getShop(10) }.await() // success! } catch (e: Exception) { // error } } ͪΐͬͱ৑௕ͩͳʜ
  40. ิॿతͳؔ਺Λ༻ҙ͢Δ // async(CommonPool)Λ؆ུԽ͢Δ fun <T> async(context: CoroutineContext = CommonPool, start:

    CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T) = kotlinx.coroutines.experimental.async(context, start, block) // launch(UI)Λ؆ུԽ͢Δ fun ui(start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit) = launch(UI, start, block)
  41. ୯ൃͷ࣮ߦ val job = ui { try { val shop

    = async { shopApi.getShop(10) }.await() // success } catch (e: Exception) { // error } }
  42. ௚ྻͷ࣮ߦ val job = ui { try { val userJob

    = async { userApi.me() } val subscriptionShopsJob = async { subscriptionShopApi.getSubscriptionShops(userJob.await().id) } val subscriptionShops = subscriptionShopsJob.await() // success } catch (e: Exception) { // error } }
  43. ௚ྻͷ࣮ߦ val job = ui { try { val userJob

    = async { userApi.me() } val subscriptionShopsJob = async { subscriptionShopApi.getSubscriptionShops(userJob.await().id) } val subscriptionShops = subscriptionShopsJob.await() // success } catch (e: Exception) { // error } } VTFS+PCͷ݁ՌΛ଴ͪ߹Θͤͨ͋ͱ࣮ߦ
  44. ฒྻͷ࣮ߦ val job = ui { try { val userJob

    = async { userApi.me() } val shopJob = async { shopApi.getShop(10L) } val user = userJob.await() val shop = shopJob.await() // success catch (e: Exception) { // error } }
  45. ฒྻͷ࣮ߦ val job = ui { try { val userJob

    = async { userApi.me() } val shopJob = async { shopApi.getShop(10L) } val user = userJob.await() val shop = shopJob.await() // success catch (e: Exception) { // error } } $PSPVUJOF4UBSU%&'"6-5Λ࢖͍ͬͯΔͷͰ ͦΕͧΕ$PNNPO1PPMͰ௚ͪʹ࣮ߦ͞ΕΔ
  46. Ωϟϯηϧ val job = launch(UI) { try { val shop

    = async(CommonPool) { shopApi.getShop(10) }.await() // success! } catch(e: CancellationException) { // cancel } catch (e: Exception) { // error } } job.cancel()
  47. Ωϟϯηϧ val job = launch(UI) { try { val shop

    = async(CommonPool) { shopApi.getShop(10) }.await() // success! } catch(e: CancellationException) { // cancel } catch (e: Exception) { // error } } job.cancel() ྫ֎ͱͯ͠ॲཧ
  48. ײ૝

  49. ײ૝ w େମ͍͚Δ ஔ͖׵͑ͯ΋Αͦ͞͏  w ௚ྻɺฒྻͷ࢖͍෼͚͕؆୯ w εϨουͷ؅ཧ͕͍ۙ৔ॴʹ͋Δ w

    ΤϥʔɺΩϟϯηϧ͕શͯྫ֎ͳͷͰϋϯυϦϯ ά͠΍͍͢ w ίϧʔνϯ΋3Y+BWBͱಉ͘͡Β͍Ԟ͕ਂ͍ͷͰ ͦ͜·Ͱؾܰʹ΍ΔͬͯΘ͚ʹ͸͍͔ͳ͍͚Ͳศ རͰ࠷ߴ
  50. ࢀߟࢿྉ w ࠓճͷίʔυ w IUUQTHJUIVCDPNTZTZBHJJNQMFNFOUBUJPOPGBTZODSFRVFTU XJUISYKBWBPSDPSPVUJOF w $PSPVUJOFTGPS,PUMJO 3FWJTJPO 

    w IUUQTHJUIVCDPN,PUMJOLPUMJODPSPVUJOFTCMPCNBTUFSLPUMJO DPSPVUJOFTJOGPSNBMNE w (VJEFUPLPUMJOYDPSPVUJOFTCZFYBNQMF w IUUQTHJUIVCDPN,PUMJOLPUMJOYDPSPVUJOFTCMPCNBTUFS DPSPVUJOFTHVJEFNE w (VJEFUP6*QSPHSBNNJOHXJUIDPSPVUJOFT w IUUQTHJUIVCDPN,PUMJOLPUMJOYDPSPVUJOFTCMPCNBTUFSVJ DPSPVUJOFTHVJEFVJNE
  51. THANK YOU