fun event() {
request()
}
suspend fun request() {
// ...
}
CoroutineScope / CoroutineBuilder
Slide 21
Slide 21 text
fun event() {
request()
}
suspend fun request() {
// ...
}
CoroutineScope / CoroutineBuilder
Suspend function 'request' should be called only from a coroutine or another suspend function
Slide 22
Slide 22 text
val scope = CoroutineScope(Dispatchers.Main)
fun event() {
scope.launch {
request()
}
}
CoroutineScope / CoroutineBuilder
Slide 23
Slide 23 text
val scope = CoroutineScope(Dispatchers.Main)
fun event() {
scope.launch {
request()
}
}
CoroutineScope / CoroutineBuilder
CoroutineScope 作成
Slide 24
Slide 24 text
val scope = CoroutineScope(Dispatchers.Main)
fun event() {
scope.launch {
request()
}
}
CoroutineScope / CoroutineBuilder
Coroutine 作成
Slide 25
Slide 25 text
Cancellation
Slide 26
Slide 26 text
val job = scope.launch {
request()
}
// ...
job.cancel()
// or
scope.cancel()
Cancellation
suspend fun request(): Data {
delay(3000)
// ...
}
val time = measureTimeMillis {
val data1 = request()
val data2 = request()
}
println("time = $time")
async / await
Slide 33
Slide 33 text
suspend fun request(): Data {
delay(3000)
// ...
}
val time = measureTimeMillis {
val data1 = request()
val data2 = request()
}
println("time = $time")
async / await
約 6000 ms
Slide 34
Slide 34 text
val time = measureTimeMillis {
val deferred1 = async { request() }
val deferred2 = async { request() }
val data1 = deferred1.await()
val data2 = deferred2.await()
}
println("time = $time")
async / await
Slide 35
Slide 35 text
val time = measureTimeMillis {
val deferred1 = async { request() }
val deferred2 = async { request() }
val data1 = deferred1.await()
val data2 = deferred2.await()
}
println("time = $time")
async / await
処理開始して待たずに次へ
Slide 36
Slide 36 text
val time = measureTimeMillis {
val deferred1 = async { request() }
val deferred2 = async { request() }
val data1 = deferred1.await()
val data2 = deferred2.await()
}
println("time = $time")
async / await
完了を待って結果を返す
Slide 37
Slide 37 text
val time = measureTimeMillis {
val deferred1 = async { request() }
val deferred2 = async { request() }
val data1 = deferred1.await()
val data2 = deferred2.await()
}
println("time = $time")
async / await
約 3000 ms
fun FusedLocationProviderClient.locationFlow() = callbackFlow {
val callback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult?) {
result ?: return
try { offer(result.lastLocation) } catch(e: Exception) {}
}
}
requestLocationUpdates(/* ... */)
.addOnFailureListener { e ->
close(e) // in case of exception, close the Flow
}
// clean up when Flow collection ends
awaitClose {
removeLocationUpdates(callback)
}
}
asLiveData vs lifecycleScope.launchWhenStarted
asLiveData vs lifecycleScope.launchWhenStarted
Activity
onStart
Active
Active
onStop
asLiveData lifecycleScope.launchWhenStarted
Observer:
Flow:
Active
Active
Collector:
Flow:
Slide 85
Slide 85 text
asLiveData vs lifecycleScope.launchWhenStarted
Activity
onStart
Active
Active
onStop
asLiveData lifecycleScope.launchWhenStarted
Cancelled
Cancelled
Observer:
Flow:
Observer:
Flow:
Active
Active
Paused
Active
Collector:
Flow:
Collector:
Flow:
Slide 86
Slide 86 text
And more...
Slide 87
Slide 87 text
New feature
Slide 88
Slide 88 text
StateFlow
Slide 89
Slide 89 text
class ViewModel {
private val _counter = MutableStateFlow(0)
val counter: StateFlow = _counter
fun increment() {
_counter.value++
}
}
lifecycleScope.launchWhenStarted {
viewModel.counter.collect {
println(it)
}
}
StateFlow
MutableLiveData:
var value: T
fun postValue(value: T)
LiveData:
val value: T
LiveData vs StateFlow
MutableStateFlow:
var value: T
StateFlow:
val value: T
Appendix
goo.gle/coroutines-posts
● Coroutines: First things first
● Cancellation in coroutines
● Exceptions in Coroutines
● The suspend modifier — Under the hood
goo.gle/coroutines-101
● Coroutines 101
codelabs.developers.google.com
● Use Kotlin Coroutines in your Android App
● Learn advanced coroutines with Kotlin Flow and LiveData
● Building a Kotlin extensions library