Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Kotlin Coroutine 基本的な使い方
Search
sutetotanuki
November 25, 2019
Programming
910
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Kotlin Coroutine 基本的な使い方
sutetotanuki
November 25, 2019
More Decks by sutetotanuki
See All by sutetotanuki
数案件を同時に進行するためのコンテキスト整理術
sutetotanuki
2
430
高速開発のためのコード整理術
sutetotanuki
1
1k
Next.js 16の新機能 Cache Components について
sutetotanuki
0
660
Vercel AI SDK を使って Next.js で AIアプリケーションを 作成する方法のご紹介
sutetotanuki
0
1.9k
WEBエンジニア向けAI活用入門
sutetotanuki
0
1.1k
ブラウザ上で実行され、 AIアシスタント付きデータベース postgres.new を触ってみた
sutetotanuki
0
580
今時のCookie事情
sutetotanuki
0
750
高速案件立ち上げで使われるマッハテンプレートのフロントエンド技術選定
sutetotanuki
2
2.1k
Core Web Vitals を改善する Next.js の機能群
sutetotanuki
1
2.7k
Other Decks in Programming
See All in Programming
【やさしく解説 設計編・中級 #4】ルールの寿命と、システムの年輪
panda728
PRO
2
180
Android CLI
fornewid
0
210
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
550
AI時代のPHPer生存戦略 ~「言語、もうなんでもよくない?」に本気で向き合う~
vivion
0
300
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
540
仕様書を書く前にハーネスを作る - Agent Native開発は「探索を速く、判定を固く」
gotalab555
4
1.6k
ソフトウェア設計に溶けるインフラ ― AWS CDK のインフラ認識論
konokenj
3
770
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
1.4k
20260722_microCMSで考える、AI時代のコンテンツ運用設計
yosh1
0
380
進化を続けるGo toolsの現在地 / The Current State of Ever-Evolving Go Tools
hond0413
0
160
複数の Claude Code が"放置"されてしまう問題をCLI ダッシュボードを自作して解決した話
sumihiro3
1
670
GDG Korea Android: 2026 I/O Extended ~ What's new in Android development tools
pluu
0
220
Featured
See All Featured
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.1k
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
230
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
420
Joys of Absence: A Defence of Solitary Play
codingconduct
1
430
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
360
The Curse of the Amulet
leimatthew05
2
14k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.4k
Everyday Curiosity
cassininazir
0
270
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
680
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
690
Side Projects
sachag
455
43k
Transcript
,PUMJO$PSPVUJOF جຊతͳ͍ํ
w Ϋϥεϝιουגࣜձࣾ w $9ࣄۀ෦ॴଐ w "1*։ൃɺ"84ڥߏஙɺӡ༻ w /&8 "OESPJE
ࠓ͢͜ͱ w $PSPVUJOFͱ w $PSPVUJOFͷ͍Έͪ w جຊతͳ͍ํ w ࣮ྫू
$PSPVUJOFͱ
$PSPVUJOFͱ w ܰྔ5ISFBE w 5ISFBEͷΑ͏ʹѻ͑ͭ͋ͨΓʹඞཁͳϦ ιʔε͕5ISFBEΑΓ͍ܰ w ͨ͘͞ΜىಈͰ͖Δ
$PSPVUJOFͷ͍ಓ 6 ϝΠϯ 6* εϨουͰߦ͏ͱ69ΛଛͶΔ Մೳੑͷ͋Δॏ͍ͨॲཧΛผεϨουͰ࣮ߦ ͢Δ
ॏ͍ͨॲཧ 7 w *0όϯυͷॲཧ w ωοτϫʔΫΞΫηε w σΟεΫΞΫηε w $16όϯυͷॲཧ
w +40/ͷγϦΞϥΠζɺσγϦΞϥΠζ w Ϧετͷฒͼସ͑
جຊతͳ͍ํ
جຊతͳ͍ํ fun main(args: Array<String>) { println("Start") GlobalScope.launch { delay(1000) println("1")
} println("2") println("End") Thread.sleep(2000) } Start 2 End 1
$PSPVUJOFͱ fun main(args: Array<String>) { println("Start") GlobalScope.launch { delay(1000) println("1")
} println("2") println("End") Thread.sleep(2000) } Start 2 End 1 $PSPVUJOFͰ࣮ߦ͞Ε ඇಉظʹॲཧ͞Ε͍ͯΔ
$PSPVUJOFͱ fun main(args: Array<String>) { println("Start") GlobalScope.launch { delay(1000) println("1")
} println("2") println("End") Thread.sleep(2000) } Start 2 End 1 $PSPVUJOF #VJMEFS $PSPVUJOF 4DPQF
$PSPVUJOF4DPQF
4DPQF֊ߏʹͰ͖Δ 4DPQFʹෳͷ$PSPVUJOFΛ࣋ͯΔ
$PSPVUJOF4DPQF fun main(args: Array<String>) = runBlocking { println("Start") GlobalScope.launch {
delay(1000) println("1") } println("2") println("End") } Start 2 End
$PSPVUJOF4DPQF fun main(args: Array<String>) = runBlocking { println("Start") GlobalScope.launch {
delay(1000) println("1") } println("2") println("End") } Start 2 End (MPCBM4DPQF ʹͳΔͨΊSVO#MPDLJOHͷ είʔϓͰऴྃΛ·ͨͳ͍
$PSPVUJOF4DPQF fun main(args: Array<String>) = runBlocking { println("Start") launch {
delay(1000) println("1") } println("2") println("End") } Start 2 End 1
$PSPVUJOFͱ fun main(args: Array<String>) = runBlocking { println("Start") launch {
delay(1000) println("1") } println("2") println("End") } Start 2 End 1 SVO#MPDLJOHͷείʔϓͷUIJT $PSPVUJOF4DPQF SVO#MPDLJOHͷ4DPQFͷMBVODIϝιουͰ ࢠ$PSPVUJOF4DPQFΛ࡞
$PSPVUJOFͱ fun main(args: Array<String>) = runBlocking { println("Start") launch {
delay(1000) println("1") } println("2") println("End") } Start 2 End 1
$PSPVUJOF %JTQBDIFST
$PSPVUJOF%JTQBDIFST 20 $PSPVUJOF͕Ͳͷ5ISFBEͰ࣮ߦ͞ΕΔ͔ ΛׂΓͯΔΈ
༻ҙ͞Ε͍ͯΔ%JTQBDIFST 21 εϨου ࠷దͳॲཧ .BJO ϝΠϯ UIΛมߋ͢ΔؔɻLiveDataͷߋ৽ *0 IOʹ࠷దԽ
ωοτϫʔΫɺσΟεΫΞΫηεͳͲ %FGBVMU όοΫάϥϯυ εϨουͷڞ༗ϓʔϧ CPUͷෛՙ͕େ͖͍ॲཧɻJSONղੳ Ϧετͷฒͼସ͑
$PSPVUJOF%JTQBDIFST fun main(args: Array<String>) = runBlocking { withContext(Dispatchers.IO) { delay(1000)
println("IO: ${Thread.currentThread().id}") } println("Main: ${Thread.currentThread().id}") } IO: 11 Main: 1
$PSPVUJOF%JTQBDIFST fun main(args: Array<String>) = runBlocking { withContext(Dispatchers.IO) { println("IO:
${Thread.currentThread().id}") } println("Main: ${Thread.currentThread().id}") } IO: 11 Main: 1 $PSPVUJOF4DPQFͷUIJTMBVODI ϝιουͰࢠ$PSPVUJOF4DPQFΛ࡞ ͢Δ
4VTQFOE
TVTQFOE 25 தஅɺ࠶։Ͱ͖ΔؔɻTVTQFOEؔ DPSPVUJOFɺ͘͠ผͷTVTQFOEؔ ͔Β͔͠ݺͳ͍
TVTQFOE suspend fun getData(): ApiResponse { return callApi() } fun
main(args: Array<String>) { getData() } Suspend function 'getData' should be called only from a coroutine or another suspend function
TVTQFOE suspend fun getData(): ApiResponse { return callApi() } fun
main(args: Array<String>) { getData() } Suspend function 'getData' should be called only from a coroutine or another suspend function ΤϥʔʹͳΔ
TVTQFOE suspend fun getData(): ApiResponse { return callApi() } fun
main(args: Array<String>) = runBlocking { getData() } DPSPVUJOFΛىಈͦ͠ͷதͰݺͿͱ Τϥʔ͕ൃੜ͠ͳ͍
࣮༻ྫ
7JFX.PEFMͰ͏ fun callApi(name: String): UserResponseBody { val client = OkHttpClient()
val request = Request.Builder() .url("https://api.github.com/users/$name") .build() client.newCall(request).execute().use {response -> return Gson().fromJson(response.body?.string(), UserResponseBody::class.java) } } class MainViewModel : ViewModel() { val response = MutableLiveData<UserResponseBody>() val userName = MutableLiveData<String>() fun getUser() { viewModelScope.launch { response.value = callApi(userName.value ?: "") } } }
7JFX.PEFMͰ͏ class MainViewModel : ViewModel() { val response = MutableLiveData<UserResponseBody>()
val userName = MutableLiveData<String>() fun getUser() { viewModelScope.launch { response.value = callApi(userName.value ?: "") } } } ϝΠϯεϨουͰΠϯλʔωοτΞΫηε ͢ΔͨΊΤϥʔʹͳΔ WJFX.PEFMͷϥΠϑαΠΫϧͰཧ͞ΕΔ WJFX.PEFM4DPQFͷ $PSPVUJOF#VJMEFSͰ$PSPVUJOFΛىಈ
ΤϥʔʹͳΒͳ͍Α͏ʹ͢Δ suspend fun callApi(name: String): UserResponseBody = withContext(Dispatchers.IO){ val client
= OkHttpClient() val request = Request.Builder() .url("https://api.github.com/users/$name") .build() client.newCall(request).execute().use {response -> Gson().fromJson(response.body?.string(), UserResponseBody::class.java) } } TVTQFOEؔʹ͢Δ %JTQBDIFST*0Ͱىಈ͢ΔΑ͏ʹࢦఆ
class MainViewModel : ViewModel() { val response = MutableLiveData<UserResponseBody>() val
userName = MutableLiveData<String>("sutetotanuki") val error = MutableLiveData<String>() fun getGithubUser() { viewModelScope.launch { try { response.value = callApi(userName.value ?: "") } catch (e: Throwable) { error.value = e.message } } } } Τϥʔॲཧ TVTQFOEؔͷΤϥʔ USZDBUDIͰर͑Δ
ίʔϧόοΫؔ $BMMCBDLΛ$PSPVUJOFͰͲ͏࣮͢Δͷ͔ Λ4USJQFͷ&QIFNFSBM,FZΛྫʹհ ͠·͢
ίʔϧόοΫؔ override suspend fun initSession() = suspendCoroutine<Unit> { con ->
CustomerSession.initCustomerSession( context, object : EphemeralKeyProvider { override fun createEphemeralKey( apiVersion: String, keyUpdateListener: EphemeralKeyUpdateListener ) { val ephemeralKeyBody = runBlocking { api.issueEphemeralKey(EphemeralKeyRequest(apiVersion)) } keyUpdateListener.onKeyUpdate(ephemeralKeyBody.string()) con.resume(Unit) } } ) }
4USJQFͷ &QIFNFSBM,FZ1SPWJEFS import androidx.annotation.Size interface EphemeralKeyProvider { fun createEphemeralKey( @Size(min
= 4) apiVersion: String, keyUpdateListener: EphemeralKeyUpdateListener ) }
4USJQFͷ &QIFNFSBM,FZ1SPWJEFS import androidx.annotation.Size interface EphemeralKeyProvider { fun createEphemeralKey( @Size(min
= 4) apiVersion: String, keyUpdateListener: EphemeralKeyUpdateListener ) } BQJ7FSTJPOΛ&QIFNFSBM,FZΛੜ͢ ΔαʔόʔαΠυͷ"1*ʹΘͨ͢ LFZ6QEBUF-JTUFOFSʹ"1*͕ੜͨ͠ &QIFNFSBM,FZΛ͢
ίʔϧόοΫؔ suspend fun initSession() = suspendCoroutine<Unit> { con -> CustomerSession.initCustomerSession(
context, object : EphemeralKeyProvider { override fun createEphemeralKey( apiVersion: String, keyUpdateListener: EphemeralKeyUpdateListener ) { val ephemeralKeyBody = runBlocking { api.issueEphemeralKey(EphemeralKeyRequest(apiVersion)) } keyUpdateListener.onKeyUpdate(ephemeralKeyBody.string()) con.resume(Unit) } } ) } BQJ͕TVTQFOEؔͰ࣮͞Ε͍ͯΔͷͰ SVO#MPDLJOHͰݺͼͩ͠ "1*ͷϨεϙϯεΛ-JTUFOFSʹઃఆ
ίʔϧόοΫؔ suspend fun initSession() = suspendCoroutine<Unit> { con -> CustomerSession.initCustomerSession(
context, object : EphemeralKeyProvider { override fun createEphemeralKey( apiVersion: String, keyUpdateListener: EphemeralKeyUpdateListener ) { val ephemeralKeyBody = runBlocking { api.issueEphemeralKey(EphemeralKeyRequest(apiVersion)) } keyUpdateListener.onKeyUpdate(ephemeralKeyBody.string()) con.resume(Unit) } } ) } -JTUFOFSʹΛͤͨͷͰ SFTVNF ෮ؼ ͢Δ
͝ਗ਼ௌ ͋Γ͕ͱ͏͍͟͝·ͨ͠