SlideShare a Scribd company logo
1 of 110
Download to read offline
NAVER |
!

Android 11 AsyncTask deprecated
“Kotlin Coroutines”
Kotlin First
Coroutines First
코루틴이뭐지?
Direct Style
fun loadItem(params: Params) {
val token = requestToken()
val item = requestItem(token, params)
showItem(item)
}
Direct Style
fun loadItem(params: Params) {
val token = requestToken()
val item = requestItem(token, params)
showItem(item)
}
Direct Style
fun loadItem(params: Params) {
val token = requestToken()
val item = requestItem(token, params)
showItem(item)
}
Continuation
onDraw() onDraw() onDraw()
Direct Style
fun loadItem(params: Params) {
val token = requestToken()
val item = requestItem(token, params)
showItem(item)
}
UI Thread
Continuation-Passing Style (CPS)
fun loadItem(params: Params) {
requestToken { token ->
val item = requestItem(token, params)
showItem(item)
}
}
Continuation-Passing Style (CPS)
fun loadItem(params: Params) {
requestToken { token ->
val item = requestItem(token, params)
showItem(item)
}
}
Continuation-Passing Style (CPS)
fun loadItem(params: Params) {
requestToken { token ->
val item = requestItem(token, params)
showItem(item)
}
}
Continuation
Callback!
Continuation-Passing Style (CPS)
fun loadItem(params: Params) {
requestToken { token ->
requestItem(token, params) { item ->
showItem(item)
}
}
}
Coroutines Direct Style
suspend fun loadItem(params: Params) {
val token = requestToken()
val item = requestItem(token, params)
showItem(item)
}
Coroutines Direct Style
suspend fun loadItem(params: Params) {
val token = requestToken()
val item = requestItem(token, params)
showItem(item)
}
onDraw() onDraw()
UI Thread
suspend resume
Coroutines Direct Style
suspend fun loadItem(params: Params) {
val token = requestToken()
val item = requestItem(token, params)
showItem(item)
}
onDraw() onDraw()
UI Thread
suspend resume
Coroutines Direct Style
suspend fun loadItem(params: Params) {
val token = requestToken()
val item = requestItem(token, params)
showItem(item)
}
코루틴은내부적으로어떻게동작할까?
CPS Transformation
suspend fun requestItem(token: Token, params: Params): Item { ... }
// Decompile bytecode in Java
Object requestItem(
Token token,
Params params,
Continuation<Item> cont
) { ... }
CPS Transformation
suspend fun requestItem(token: Token, params: Params): Item { ... }
// Decompile bytecode in Java
Object requestItem(
Token token,
Params params,
Continuation<Item> cont
) { ... }
CPS Transformation
interface Continuation<in T> {
val context: CoroutineContext
fun resumeWith(result: Result<T>)
}
CPS Transformation
interface Continuation<in T> {
val context: CoroutineContext
fun resumeWith(result: Result<T>)
}
CPS Transformation
suspend fun loadItem(params: Params) {
val token = requestToken()
val item = requestItem(token, params)
showItem(item)
}
CPS Transformation
suspend fun loadItem(params: Params) {
val token = requestToken()
val item = requestItem(token, params)
showItem(item)
}
Initial
Continuation
CPS Transformation
suspend fun loadItem(params: Params) {
val token = requestToken()
val item = requestItem(token, params)
showItem(item)
}
Continuation
CPS Transformation
suspend fun loadItem(params: Params) {
val token = requestToken()
val item = requestItem(token, params)
showItem(item)
}
Continuation
Callback ???
fun loadItem(params: Params) {
requestToken { token ->
requestItem(token, params) { item ->
showItem(item)
}
}
}
CPS Transformation
suspend fun loadItem(params: Params) {
// LABEL 0
val token = requestToken()
// LABEL 1
val item = requestItem(token, params)
// LABEL 2
showItem(item)
}
CPS Transformation
suspend fun loadItem(params: Params) {
val sm = object : ContinuationImpl { ... }
when (sm.label) {
0 -> val token = requestToken()
1 -> val item = requestItem(token, params)
2 -> showItem(item)
}
}
CPS Transformation
suspend fun loadItem(params: Params) {
val sm = object : ContinuationImpl { ... }
when (sm.label) {
0 -> val token = requestToken()
1 -> val item = requestItem(token, params)
2 -> showItem(item)
}
}
State Machine
CPS Transformation
fun loadItem(params: Params, cont: Continuation) {
val sm = object : ContinuationImpl { ... }
when (sm.label) {
0 -> requestToken(sm)
1 -> requestItem(token, params, sm)
2 -> showItem(item)
}
}
CPS Transformation
fun loadItem(params: Params, cont: Continuation) {
val sm = object : ContinuationImpl { ... }
when (sm.label) {
0 -> {
sm.params = params
sm.label = 1
requestToken(sm)
}
1 -> requestItem(token, params, sm)
2 -> showItem(item)
}
}
CPS Transformation
fun loadItem(params: Params, cont: Continuation) {
val sm = object : ContinuationImpl { ... }
when (sm.label) {
0 -> {
sm.params = params
sm.label = 1
requestToken(sm)
}
1 -> requestItem(token, params, sm)
2 -> showItem(item)
}
}
CPS Transformation
fun loadItem(params: Params, cont: Continuation) {
val sm = object : ContinuationImpl { ... }
when (sm.label) {
0 -> {
sm.params = params
sm.label = 1
requestToken(sm)
}
1 -> requestItem(token, params, sm)
2 -> showItem(item)
}
}
State Machine
Continuation
CPS Transformation
fun loadItem(params: Params, cont: Continuation) {
val sm = cont as? ThisSM ?: object : ThisSM {
fun resumeWith(...) {
loadItem(null, this) {
}
}
...
}
CPS Transformation
fun loadItem(params: Params, cont: Continuation) {
val sm = ...
when (sm.label) {
0 -> { ... }
1 -> {
val params = sm.params
val token = sm.result as Token
sm.label = 2
requestItem(token, params, sm)
}
2 -> { ... }
}
}
CPS Transformation
fun loadItem(params: Params, cont: Continuation) {
val sm = ...
when (sm.label) {
0 -> { ... }
1 -> {
val params = sm.params
val token = sm.result as Token
sm.label = 2
requestItem(token, params, sm)
}
2 -> { ... }
}
}
CPS Transformation
fun loadItem(params: Params, cont: Continuation) {
val sm = ...
when (sm.label) {
0 -> { ... }
1 -> {
val params = sm.params
val token = sm.result as Token
sm.label = 2
requestItem(token, params, sm)
}
2 -> { ... }
}
}
State Machine vs. Callback
•State Machine 은 상태를 저장한 하나의 객체를 공유하지만, Callback 은 매번 closure를 생성해야 함

•복잡한 구조에 대응하기 쉬움
suspend fun loadItems(params: List<Params>) {
for (p in params) {
val token = requestToken()
val item = requestItem(token, p)
showItem(item)
}
}
그래서코루틴을왜쓰는거지?
Why Coroutines ?
• Structured concurrency
➡ 구조화된 동시성 처리로 memory leak 방지
Structured Concurrency
@CheckReturnValue
@BackpressureSupport(BackpressureKind.UNBOUNDED_IN)
@SchedulerSupport(SchedulerSupport.NONE)
public final Disposable subscribe(Consumer<? super T> onNext) {
return subscribe(onNext, Functions.ON_ERROR_MISSING,
Functions.EMPTY_ACTION,
FlowableInternalHelper.RequestMax.INSTANCE);
}
Structured Concurrency
fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job { ... }
• RxJava leak warn
• CoroutineScope leak
Why Coroutines ?
• Structured concurrency
➡ 구조화된 동시성 처리로 memory leak 방지
• Light weight
➡ 싱글 스레드에서 여러 코루틴을 동시에 실행할 수 있음 (동시성)
Kotlin Flow: Reactive scrabble benchmarks
•Java 8 Stream - RxJava 간 성능 비교를 위해 José Paumard 에 의해 개발됨

•Rx 관련 코드는 David Karnok 가 작성
https://github.com/Kotlin/kotlinx.coroutines/tree/master/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble
Why Coroutines ?
• Structured concurrency
➡ 구조화된 동시성 처리로 memory leak 방지
• Light weight
➡ 싱글 스레드에서 여러 코루틴을 동시에 실행할 수 있음 (동시성)
• Built-in cancellation
➡ 계층 구조를 따라 취소가 자동으로 전파됨
• Simplify asynchronous code
➡ 비동기 코드를 콜백 대신 순차적(sequential)인 코드로 작성할 수 있음
➡ 다양한 Jetpack 라이브러리에서 extensions 등의 형태로 코루틴을 지원
내앱에코루틴을적용해보자!
, CoroutineScope
interface CoroutineScope {
val coroutineContext: CoroutineContext
}
•새로운 코루틴을 시작하는 코루틴 빌더는 모두 CoroutineScope 의 extensions function 으로 구성
, launch() & async()
fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job { ... }
fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T> { ... }
launch() vs. async()
•
• CoroutineScope
• suspend function
Exception .await() Exception X
launch() async()
launch()
val job = launch {
delay(1000)
doSomething()
}
async()
private suspend fun mergeApi(): List<Item> = coroutineScope {
val deferredOne = async { fetchApiOne() }
val deferredTwo = async { fetchApiTwo() }
return deferredOne.await() + deferredTwo.await()
}
private suspend fun mergeApi(): List<Item> = coroutineScope {
val deferredOne = async { fetchApiOne() }
val deferredTwo = async { fetchApiTwo() }
return deferredOne.await() + deferredTwo.await()
}
async()
fetchApiOne() ,
fetchApiTwo()
async()
private suspend fun mergeApi(): List<Item> = coroutineScope {
val deferredOne = async { fetchApiOne() }
val deferredTwo = async { fetchApiTwo() }
return deferredOne.await() + deferredTwo.await()
}
suspend
GlobalScope
object GlobalScope : CoroutineScope {
override val coroutineContext: CoroutineContext
get() = EmptyCoroutineContext
}
•앱 전체 생명주기로 동작하는 top-level CoroutineScope

•대부분의 경우에 사용하면 안됨
GlobalScope
fun ReceiveChannel<Int>.sqrt(): ReceiveChannel<Double> =
GlobalScope.produce(Dispatchers.Unconfined) {
for (number in this) {
send(Math.sqrt(number))
}
}
ViewModel
Jetpack ViewModel
Kotlin Property Delegates for ViewModels
class AwesomeFragment : Fragment() {
private val model: AwesomeViewModel by viewModels()
}
Kotlin Property Delegates for ViewModels
class AwesomeFragment : Fragment() {
private val model: AwesomeViewModel by viewModels()
private fun showChildFragment() = childFragmentManager.commit {
replace(R.id.fragment_child, ChildFragment())
}
}
class ChildFragment : Fragment() { ... }
Kotlin Property Delegates for ViewModels
class AwesomeFragment : Fragment() {
private val model: AwesomeViewModel by viewModels()
private fun showChildFragment() = childFragmentManager.commit {
replace(R.id.fragment_child, ChildFragment())
}
}
class ChildFragment : Fragment() {
private val model: AwesomeViewModel by viewModels({ requireParentFragment() })
}
Kotlin Property Delegates for ViewModels
class AwesomeFragment : Fragment() {
private val model: AwesomeViewModel by viewModels()
private fun showChildFragment() = childFragmentManager.commit {
replace(R.id.fragment_child, ChildFragment())
}
}
class ChildFragment : Fragment() {
private val model: AwesomeViewModel by viewModels({ requireParentFragment() })
}
Kotlin Property Delegates for ViewModels
class AwesomeActivity : AppCompatActivity() {
private val sharedModel: SharedViewModel by viewModels()
}
class AwesomeFragment : Fragment() {
private val sharedModel: SharedViewModel by activityViewModels()
}
class ChildFragment : Fragment() {
private val sharedModel: SharedViewModel by activityViewModels()
}
Kotlin Property Delegates for ViewModels
class AwesomeActivity : AppCompatActivity() {
private val sharedModel: SharedViewModel by viewModels()
}
class AwesomeFragment : Fragment() {
private val sharedModel: SharedViewModel by activityViewModels()
}
class ChildFragment : Fragment() {
private val sharedModel: SharedViewModel by activityViewModels()
}
CoroutineScope ViewModel
class AwesomeViewModel : ViewModel(), CoroutineScope {
override val coroutineContext: CoroutineContext
get() = EmptyCoroutineContext
}
Context
class AwesomeViewModel : ViewModel(), CoroutineScope {
override val coroutineContext: CoroutineContext
get() = EmptyCoroutineContext
}
CoroutineContext
CoroutineContext
• Job
➡ Lifecycle
• CoroutineDispatcher
➡ Threading
• CoroutineExceptionHandler
• CoroutineName
CoroutineContext’s Default
• Job
➡ No parent job
• CoroutineDispatcher
➡ Dispatchers.Default
• CoroutineExceptionHandler
➡ None
• CoroutineName
➡ “coroutine”
context
CoroutineContext
public interface CoroutineContext {
public operator fun <E : Element> get(key: Key<E>): E?
public fun <R> fold(initial: R, operation: (R, Element) -> R): R
public operator fun plus(context: CoroutineContext): CoroutineContext = ...
public fun minusKey(key: Key<*>): CoroutineContext
public interface Key<E : Element>
public interface Element : CoroutineContext { ... }
}
CoroutineContext
public interface CoroutineContext {
public operator fun <E : Element> get(key: Key<E>): E?
public fun <R> fold(initial: R, operation: (R, Element) -> R): R
public operator fun plus(context: CoroutineContext): CoroutineContext = ...
public fun minusKey(key: Key<*>): CoroutineContext
public interface Key<E : Element>
public interface Element : CoroutineContext { ... }
}
CoroutineContext
public interface CoroutineContext {
public operator fun <E : Element> get(key: Key<E>): E?
public fun <R> fold(initial: R, operation: (R, Element) -> R): R
public operator fun plus(context: CoroutineContext): CoroutineContext = ...
public fun minusKey(key: Key<*>): CoroutineContext
public interface Key<E : Element>
public interface Element : CoroutineContext { ... }
}
CoroutineContext
public interface CoroutineContext {
public operator fun <E : Element> get(key: Key<E>): E?
public fun <R> fold(initial: R, operation: (R, Element) -> R): R
public operator fun plus(context: CoroutineContext): CoroutineContext = ...
public fun minusKey(key: Key<*>): CoroutineContext
public interface Key<E : Element>
public interface Element : CoroutineContext { ... }
}
CoroutineContext
public interface CoroutineContext {
public operator fun <E : Element> get(key: Key<E>): E?
public fun <R> fold(initial: R, operation: (R, Element) -> R): R
public operator fun plus(context: CoroutineContext): CoroutineContext = ...
public fun minusKey(key: Key<*>): CoroutineContext
public interface Key<E : Element>
public interface Element : CoroutineContext { ... }
}
CoroutineContext
public interface CoroutineContext {
public operator fun <E : Element> get(key: Key<E>): E?
public fun <R> fold(initial: R, operation: (R, Element) -> R): R
public operator fun plus(context: CoroutineContext): CoroutineContext = ...
public fun minusKey(key: Key<*>): CoroutineContext
public interface Key<E : Element>
public interface Element : CoroutineContext { ... }
}
CoroutineContext
public interface CoroutineContext {
public operator fun <E : Element> get(key: Key<E>): E?
public fun <R> fold(initial: R, operation: (R, Element) -> R): R
public operator fun plus(context: CoroutineContext): CoroutineContext = ...
public fun minusKey(key: Key<*>): CoroutineContext
public interface Key<E : Element>
public interface Element : CoroutineContext { ... }
}
CoroutineContext
public interface CoroutineContext {
public operator fun <E : Element> get(key: Key<E>): E?
public fun <R> fold(initial: R, operation: (R, Element) -> R): R
public operator fun plus(context: CoroutineContext): CoroutineContext = ...
public fun minusKey(key: Key<*>): CoroutineContext
public interface Key<E : Element>
public interface Element : CoroutineContext { ... }
}
coroutineContext[Job]
CoroutineContext
public interface CoroutineContext {
public operator fun <E : Element> get(key: Key<E>): E?
public fun <R> fold(initial: R, operation: (R, Element) -> R): R
public operator fun plus(context: CoroutineContext): CoroutineContext = ...
public fun minusKey(key: Key<*>): CoroutineContext
public interface Key<E : Element>
public interface Element : CoroutineContext { ... }
}
Job() + Dispathchers.IO
Job
• (Lifecycle)
wait children
+-----+ start +--------+ complete +-------------+ finish +-----------+
| New | -----> | Active | ---------> | Completing | -------> | Completed |
+-----+ +--------+ +-------------+ +-----------+
| cancel / fail |
| +----------------+
| |
V V
+------------+ finish +-----------+
| Cancelling | --------------------------------> | Cancelled |
+------------+ +-----------+
Job
• (Hierarchy)
Parent Job
Child Job Child Job Child Job Child Job
Job
class AwesomeViewModel : ViewModel(), CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job
override fun onCleared() {
super.onCleared()
job.cancel()
}
}
•When a child fails, it propagates cancellation to other children

•When a failure is notified, the scope propagates the exception up
SupervisorJob
class AwesomeViewModel : ViewModel(), CoroutineScope {
private val job = SupervisorJob()
override val coroutineContext: CoroutineContext
get() = job
override fun onCleared() {
super.onCleared()
job.cancel()
}
}
•The failure of a child doesn't affect other children

•When a failure is notified, the scope doesn't do anything
Cooperative cancellation
repeat (5) {
someBlockingTask()
}
repeat (5) {
yield() // or ensureActive()
someBlockingTask()
}
Cooperative cancellation
while (true) {
someBlockingTask()
}
while (isActive) {
someBlockingTask()
}
Dispatchers
actual object Dispatchers {
@JvmStatic
actual val Default: CoroutineDispatcher = createDefaultDispatcher()
@JvmStatic
actual val Main: MainCoroutineDispatcher get() = MainDispatcherLoader.dispatcher
@JvmStatic
actual val Unconfined: CoroutineDispatcher = kotlinx.coroutines.Unconfined
@JvmStatic
val IO: CoroutineDispatcher = DefaultScheduler.IO
}
Main-safe suspend function
suspend fun mainSafeFunc() {
val result = withContext(Dispatchers.IO) {
fetchApi()
}
return result.name
}
• Main(UI) Thread suspend function withContext
➡ e.g. Retrofit 2.6.0+ suspend function
Job + Dispatchers
class AwesomeViewModel : ViewModel(), CoroutineScope {
private val job = SupervisorJob()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCleared() {
super.onCleared()
job.cancel()
}
}
class AwesomeViewModel : ViewModel(), CoroutineScope {
private val job = SupervisorJob()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
init {
launch {
// Call suspend func.
}
}
override fun onCleared() {
super.onCleared()
job.cancel()
}
}
Lifecycle-aware coroutine scopes
•For ViewModelScope, use androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0-beta01 or higher.
class PlainViewModel : ViewModel() {
init {
viewModelScope.launch {
// Call suspend func.
}
}
}
Lifecycle-aware coroutine scopes
•For LifecycleScope, use androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha01 or higher.
// Activity or Fragment
class PlainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
// Call suspend func.
}
lifecycleScope.launchWhenResumed {
// Call suspend func.
}
}
}
코루틴과LiveData
ViewModel + LiveData
ViewModel + LiveData
class PlainViewModel : ViewModel() {
private val _result = MutableLiveData<String>()
val result: LiveData<String> = _result
init {
viewModelScope.launch {
val computationResult = doComputation()
_result.value = computationResult
}
}
}
LiveData Builder
•For liveData, use androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01 or higher.
class PlainViewModel : ViewModel() {
val result: LiveData {
emit(doComputation())
}
}
LiveData Builder
class PlainViewModel : ViewModel() {
// itemId item
private val itemId = MutableLiveData<String>()
val result = itemId.switchMap {
liveData { emit(fetchItem(it)) }
}
// LiveData
val weather = liveData(Dispatchers.IO) {
emit(LOADING_STRING)
emitSource(dataSource.fetchWeather()) // LiveData
}
}
StateFlow
• LiveData State holder !
• state StateFlow
interface StateFlow<T> : Flow<T> {
val value: T
// always available, reading it never fails
}
interface MutableStateFlow<T> : StateFlow<T> {
override var value: T
// can read & write value
}
fun <T> MutableStateFlow(value: T): MutableStateFlow<T>
// constructor fun
SharedFlow
https://github.com/Kotlin/kotlinx.coroutines/pull/2069
Paging
Paging 2
class AwesomeDataSource(parent: Job? = null) : PositionalDataSource<Awesome>(), CoroutineScope {
private val job = SupervisorJob(parent)
override val coroutineContext: CoroutineContext
get() = Dispatchers.Unconfined + job
override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback<Awesome>) {
launch {
runCatching { loadInternal(params.requestedStartPosition, params.requestedLoadSize) }
.fold(
onSuccess = { callback.onResult(it, params.requestedStartPosition) },
onFailure = { callback.onResult(emptyList(), params.requestedStartPosition) }
)
}
}
...
}
Paging 3
•First-class support for Kotlin coroutines and Flow, as well as LiveData and RxJava.

•현재 알파 버전 (3.0.0-alpha04)
Paging 3
@ExperimentalPagingApi
abstract class RemoteMediator<Key : Any, Value : Any> {
abstract suspend fun load(loadType: LoadType, state: PagingState<Key, Value>): MediatorResult
...
}
Single source of truth
RxJava-Coroutines상호변환
RxJava - Coroutines
https://github.com/Kotlin/kotlinx.coroutines/tree/master/reactive/kotlinx-coroutines-rx2
RxJava - Coroutines
RxJava - Coroutines
RxJava - Coroutines
RxJava - Coroutines
// Coroutines -> Rx
val single = rxSingle {
// call suspend func.
}
// Rx -> Coroutines
val result = single.await()
Coroutines
suspend fun request(id: String): Awesome = suspendCancellableCoroutine { cont ->
cont.invokeOnCancellation {
// Cancel execution.
}
awesomeModelProvider
.request(id)
.execute(object : Response {
override fun onSuccess(items: Awesome) {
cont.resume(items)
}
override fun onError(message: String?) {
cont.resumeWithException(IOException(message))
}
})
}
launch {
textView.text = request(id).name
}
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드

More Related Content

What's hot

#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기Arawn Park
 
새해 일어난 일
새해 일어난 일새해 일어난 일
새해 일어난 일Eunhyang Kim
 
Kotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKirill Rozov
 
[부스트캠퍼세미나]김재원_presentation-oop
[부스트캠퍼세미나]김재원_presentation-oop[부스트캠퍼세미나]김재원_presentation-oop
[부스트캠퍼세미나]김재원_presentation-oopCONNECT FOUNDATION
 
Analysing in depth work manager
Analysing in depth work managerAnalysing in depth work manager
Analysing in depth work managerbhatnagar.gaurav83
 
Webpack Introduction
Webpack IntroductionWebpack Introduction
Webpack IntroductionAnjali Chawla
 
Sync async-blocking-nonblocking-io
Sync async-blocking-nonblocking-ioSync async-blocking-nonblocking-io
Sync async-blocking-nonblocking-ioCheoloh Bae
 
[부스트캠프 웹・모바일 7기 Tech Talk]이지훈_뉴비의 시점에서 바라본 Kotlin_suspend
[부스트캠프 웹・모바일 7기 Tech Talk]이지훈_뉴비의 시점에서 바라본 Kotlin_suspend[부스트캠프 웹・모바일 7기 Tech Talk]이지훈_뉴비의 시점에서 바라본 Kotlin_suspend
[부스트캠프 웹・모바일 7기 Tech Talk]이지훈_뉴비의 시점에서 바라본 Kotlin_suspendCONNECT FOUNDATION
 
Server-side JS with NodeJS
Server-side JS with NodeJSServer-side JS with NodeJS
Server-side JS with NodeJSLilia Sfaxi
 
JavaScript Event Loop
JavaScript Event LoopJavaScript Event Loop
JavaScript Event LoopDesignveloper
 
우아한 모노리스
우아한 모노리스우아한 모노리스
우아한 모노리스Arawn Park
 
Certificate 와 Provisioning Profile
Certificate 와 Provisioning ProfileCertificate 와 Provisioning Profile
Certificate 와 Provisioning Profilessuser9054541
 
게임서버프로그래밍 #2 - IOCP Adv
게임서버프로그래밍 #2 - IOCP Adv게임서버프로그래밍 #2 - IOCP Adv
게임서버프로그래밍 #2 - IOCP AdvSeungmo Koo
 
유니티 + Nodejs를 활용한 멀티플레이어 게임 개발하기
유니티 + Nodejs를 활용한 멀티플레이어 게임 개발하기유니티 + Nodejs를 활용한 멀티플레이어 게임 개발하기
유니티 + Nodejs를 활용한 멀티플레이어 게임 개발하기Kiyoung Moon
 
웹 크롤링 (Web scraping) 의 이해
웹 크롤링 (Web scraping) 의 이해웹 크롤링 (Web scraping) 의 이해
웹 크롤링 (Web scraping) 의 이해2minchul
 
날로 먹는 Django admin 활용
날로 먹는 Django admin 활용날로 먹는 Django admin 활용
날로 먹는 Django admin 활용KyeongMook "Kay" Cha
 
NodeJS guide for beginners
NodeJS guide for beginnersNodeJS guide for beginners
NodeJS guide for beginnersEnoch Joshua
 
게임서버프로그래밍 #0 - TCP 및 이벤트 통지모델
게임서버프로그래밍 #0 - TCP 및 이벤트 통지모델게임서버프로그래밍 #0 - TCP 및 이벤트 통지모델
게임서버프로그래밍 #0 - TCP 및 이벤트 통지모델Seungmo Koo
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOPDzmitry Naskou
 
Angular Data Binding
Angular Data BindingAngular Data Binding
Angular Data BindingDuy Khanh
 

What's hot (20)

#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
 
새해 일어난 일
새해 일어난 일새해 일어난 일
새해 일어난 일
 
Kotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is coming
 
[부스트캠퍼세미나]김재원_presentation-oop
[부스트캠퍼세미나]김재원_presentation-oop[부스트캠퍼세미나]김재원_presentation-oop
[부스트캠퍼세미나]김재원_presentation-oop
 
Analysing in depth work manager
Analysing in depth work managerAnalysing in depth work manager
Analysing in depth work manager
 
Webpack Introduction
Webpack IntroductionWebpack Introduction
Webpack Introduction
 
Sync async-blocking-nonblocking-io
Sync async-blocking-nonblocking-ioSync async-blocking-nonblocking-io
Sync async-blocking-nonblocking-io
 
[부스트캠프 웹・모바일 7기 Tech Talk]이지훈_뉴비의 시점에서 바라본 Kotlin_suspend
[부스트캠프 웹・모바일 7기 Tech Talk]이지훈_뉴비의 시점에서 바라본 Kotlin_suspend[부스트캠프 웹・모바일 7기 Tech Talk]이지훈_뉴비의 시점에서 바라본 Kotlin_suspend
[부스트캠프 웹・모바일 7기 Tech Talk]이지훈_뉴비의 시점에서 바라본 Kotlin_suspend
 
Server-side JS with NodeJS
Server-side JS with NodeJSServer-side JS with NodeJS
Server-side JS with NodeJS
 
JavaScript Event Loop
JavaScript Event LoopJavaScript Event Loop
JavaScript Event Loop
 
우아한 모노리스
우아한 모노리스우아한 모노리스
우아한 모노리스
 
Certificate 와 Provisioning Profile
Certificate 와 Provisioning ProfileCertificate 와 Provisioning Profile
Certificate 와 Provisioning Profile
 
게임서버프로그래밍 #2 - IOCP Adv
게임서버프로그래밍 #2 - IOCP Adv게임서버프로그래밍 #2 - IOCP Adv
게임서버프로그래밍 #2 - IOCP Adv
 
유니티 + Nodejs를 활용한 멀티플레이어 게임 개발하기
유니티 + Nodejs를 활용한 멀티플레이어 게임 개발하기유니티 + Nodejs를 활용한 멀티플레이어 게임 개발하기
유니티 + Nodejs를 활용한 멀티플레이어 게임 개발하기
 
웹 크롤링 (Web scraping) 의 이해
웹 크롤링 (Web scraping) 의 이해웹 크롤링 (Web scraping) 의 이해
웹 크롤링 (Web scraping) 의 이해
 
날로 먹는 Django admin 활용
날로 먹는 Django admin 활용날로 먹는 Django admin 활용
날로 먹는 Django admin 활용
 
NodeJS guide for beginners
NodeJS guide for beginnersNodeJS guide for beginners
NodeJS guide for beginners
 
게임서버프로그래밍 #0 - TCP 및 이벤트 통지모델
게임서버프로그래밍 #0 - TCP 및 이벤트 통지모델게임서버프로그래밍 #0 - TCP 및 이벤트 통지모델
게임서버프로그래밍 #0 - TCP 및 이벤트 통지모델
 
Spring Framework - AOP
Spring Framework - AOPSpring Framework - AOP
Spring Framework - AOP
 
Angular Data Binding
Angular Data BindingAngular Data Binding
Angular Data Binding
 

Similar to 200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드

Programação assíncrona utilizando Coroutines
Programação assíncrona utilizando CoroutinesProgramação assíncrona utilizando Coroutines
Programação assíncrona utilizando CoroutinesDiego Gonçalves Santos
 
TDC2018SP | Trilha Kotlin - Programacao assincrona utilizando Coroutines
TDC2018SP | Trilha Kotlin - Programacao assincrona utilizando CoroutinesTDC2018SP | Trilha Kotlin - Programacao assincrona utilizando Coroutines
TDC2018SP | Trilha Kotlin - Programacao assincrona utilizando Coroutinestdc-globalcode
 
Kotlin coroutine - behind the scenes
Kotlin coroutine - behind the scenesKotlin coroutine - behind the scenes
Kotlin coroutine - behind the scenesAnh Vu
 
Coroutines in Kotlin. In-depth review
Coroutines in Kotlin. In-depth reviewCoroutines in Kotlin. In-depth review
Coroutines in Kotlin. In-depth reviewDmytro Zaitsev
 
Coroutines in Kotlin. UA Mobile 2017.
Coroutines in Kotlin. UA Mobile 2017.Coroutines in Kotlin. UA Mobile 2017.
Coroutines in Kotlin. UA Mobile 2017.UA Mobile
 
Should it be routine to use coroutines?
Should it be routine to use coroutines?Should it be routine to use coroutines?
Should it be routine to use coroutines?Ion Stefan Brosteanu
 
Programação Assíncrona com Kotlin Coroutines
Programação Assíncrona com Kotlin CoroutinesProgramação Assíncrona com Kotlin Coroutines
Programação Assíncrona com Kotlin CoroutinesLucas Borsatto
 
Fresh Async with Kotlin @ QConSF 2017
Fresh Async with Kotlin @ QConSF 2017Fresh Async with Kotlin @ QConSF 2017
Fresh Async with Kotlin @ QConSF 2017Roman Elizarov
 
Kotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresKotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresiMasters
 
C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴명신 김
 
JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?PROIDEA
 
Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Alex Semin
 
Dive into kotlins coroutines
Dive into kotlins coroutinesDive into kotlins coroutines
Dive into kotlins coroutinesFreddie Wang
 
Cocoa Design Patterns in Swift
Cocoa Design Patterns in SwiftCocoa Design Patterns in Swift
Cocoa Design Patterns in SwiftMichele Titolo
 
Implementing STM in Java
Implementing STM in JavaImplementing STM in Java
Implementing STM in JavaMisha Kozik
 
JVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in KotlinJVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in KotlinAndrey Breslav
 

Similar to 200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드 (20)

Programação assíncrona utilizando Coroutines
Programação assíncrona utilizando CoroutinesProgramação assíncrona utilizando Coroutines
Programação assíncrona utilizando Coroutines
 
TDC2018SP | Trilha Kotlin - Programacao assincrona utilizando Coroutines
TDC2018SP | Trilha Kotlin - Programacao assincrona utilizando CoroutinesTDC2018SP | Trilha Kotlin - Programacao assincrona utilizando Coroutines
TDC2018SP | Trilha Kotlin - Programacao assincrona utilizando Coroutines
 
Kotlin coroutine - behind the scenes
Kotlin coroutine - behind the scenesKotlin coroutine - behind the scenes
Kotlin coroutine - behind the scenes
 
Coroutines in Kotlin. In-depth review
Coroutines in Kotlin. In-depth reviewCoroutines in Kotlin. In-depth review
Coroutines in Kotlin. In-depth review
 
Coroutines in Kotlin. UA Mobile 2017.
Coroutines in Kotlin. UA Mobile 2017.Coroutines in Kotlin. UA Mobile 2017.
Coroutines in Kotlin. UA Mobile 2017.
 
Should it be routine to use coroutines?
Should it be routine to use coroutines?Should it be routine to use coroutines?
Should it be routine to use coroutines?
 
Programação Assíncrona com Kotlin Coroutines
Programação Assíncrona com Kotlin CoroutinesProgramação Assíncrona com Kotlin Coroutines
Programação Assíncrona com Kotlin Coroutines
 
Kotlin coroutines
Kotlin coroutines Kotlin coroutines
Kotlin coroutines
 
Fresh Async with Kotlin @ QConSF 2017
Fresh Async with Kotlin @ QConSF 2017Fresh Async with Kotlin @ QConSF 2017
Fresh Async with Kotlin @ QConSF 2017
 
Php sql-android
Php sql-androidPhp sql-android
Php sql-android
 
Kotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresKotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan Soares
 
C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴
 
JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?
 
Kotlin, why?
Kotlin, why?Kotlin, why?
Kotlin, why?
 
Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303
 
Dive into kotlins coroutines
Dive into kotlins coroutinesDive into kotlins coroutines
Dive into kotlins coroutines
 
Cocoa Design Patterns in Swift
Cocoa Design Patterns in SwiftCocoa Design Patterns in Swift
Cocoa Design Patterns in Swift
 
Implementing STM in Java
Implementing STM in JavaImplementing STM in Java
Implementing STM in Java
 
JVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in KotlinJVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in Kotlin
 
Kotlin Coroutines and Rx
Kotlin Coroutines and RxKotlin Coroutines and Rx
Kotlin Coroutines and Rx
 

More from NAVER Engineering

디자인 시스템에 직방 ZUIX
디자인 시스템에 직방 ZUIX디자인 시스템에 직방 ZUIX
디자인 시스템에 직방 ZUIXNAVER Engineering
 
진화하는 디자인 시스템(걸음마 편)
진화하는 디자인 시스템(걸음마 편)진화하는 디자인 시스템(걸음마 편)
진화하는 디자인 시스템(걸음마 편)NAVER Engineering
 
서비스 운영을 위한 디자인시스템 프로젝트
서비스 운영을 위한 디자인시스템 프로젝트서비스 운영을 위한 디자인시스템 프로젝트
서비스 운영을 위한 디자인시스템 프로젝트NAVER Engineering
 
BPL(Banksalad Product Language) 무야호
BPL(Banksalad Product Language) 무야호BPL(Banksalad Product Language) 무야호
BPL(Banksalad Product Language) 무야호NAVER Engineering
 
이번 생에 디자인 시스템은 처음이라
이번 생에 디자인 시스템은 처음이라이번 생에 디자인 시스템은 처음이라
이번 생에 디자인 시스템은 처음이라NAVER Engineering
 
날고 있는 여러 비행기 넘나 들며 정비하기
날고 있는 여러 비행기 넘나 들며 정비하기날고 있는 여러 비행기 넘나 들며 정비하기
날고 있는 여러 비행기 넘나 들며 정비하기NAVER Engineering
 
쏘카프레임 구축 배경과 과정
 쏘카프레임 구축 배경과 과정 쏘카프레임 구축 배경과 과정
쏘카프레임 구축 배경과 과정NAVER Engineering
 
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기NAVER Engineering
 
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)NAVER Engineering
 
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기NAVER Engineering
 
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활NAVER Engineering
 
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출NAVER Engineering
 
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우NAVER Engineering
 
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...NAVER Engineering
 
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법NAVER Engineering
 
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며NAVER Engineering
 
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기NAVER Engineering
 
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기NAVER Engineering
 
200819 NAVER TECH CONCERT 06_놓치기 쉬운 안드로이드 UI 디테일 살펴보기
200819 NAVER TECH CONCERT 06_놓치기 쉬운 안드로이드 UI 디테일 살펴보기200819 NAVER TECH CONCERT 06_놓치기 쉬운 안드로이드 UI 디테일 살펴보기
200819 NAVER TECH CONCERT 06_놓치기 쉬운 안드로이드 UI 디테일 살펴보기NAVER Engineering
 

More from NAVER Engineering (20)

React vac pattern
React vac patternReact vac pattern
React vac pattern
 
디자인 시스템에 직방 ZUIX
디자인 시스템에 직방 ZUIX디자인 시스템에 직방 ZUIX
디자인 시스템에 직방 ZUIX
 
진화하는 디자인 시스템(걸음마 편)
진화하는 디자인 시스템(걸음마 편)진화하는 디자인 시스템(걸음마 편)
진화하는 디자인 시스템(걸음마 편)
 
서비스 운영을 위한 디자인시스템 프로젝트
서비스 운영을 위한 디자인시스템 프로젝트서비스 운영을 위한 디자인시스템 프로젝트
서비스 운영을 위한 디자인시스템 프로젝트
 
BPL(Banksalad Product Language) 무야호
BPL(Banksalad Product Language) 무야호BPL(Banksalad Product Language) 무야호
BPL(Banksalad Product Language) 무야호
 
이번 생에 디자인 시스템은 처음이라
이번 생에 디자인 시스템은 처음이라이번 생에 디자인 시스템은 처음이라
이번 생에 디자인 시스템은 처음이라
 
날고 있는 여러 비행기 넘나 들며 정비하기
날고 있는 여러 비행기 넘나 들며 정비하기날고 있는 여러 비행기 넘나 들며 정비하기
날고 있는 여러 비행기 넘나 들며 정비하기
 
쏘카프레임 구축 배경과 과정
 쏘카프레임 구축 배경과 과정 쏘카프레임 구축 배경과 과정
쏘카프레임 구축 배경과 과정
 
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
플랫폼 디자이너 없이 디자인 시스템을 구축하는 프로덕트 디자이너의 우당탕탕 고통 연대기
 
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
200820 NAVER TECH CONCERT 15_Code Review is Horse(코드리뷰는 말이야)(feat.Latte)
 
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
200819 NAVER TECH CONCERT 10_맥북에서도 아이맥프로에서 빌드하는 것처럼 빌드 속도 빠르게 하기
 
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
200819 NAVER TECH CONCERT 08_성능을 고민하는 슬기로운 개발자 생활
 
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
200819 NAVER TECH CONCERT 05_모르면 손해보는 Android 디버깅/분석 꿀팁 대방출
 
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
200819 NAVER TECH CONCERT 09_Case.xcodeproj - 좋은 동료로 거듭나기 위한 노하우
 
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
200820 NAVER TECH CONCERT 14_야 너두 할 수 있어. 비전공자, COBOL 개발자를 거쳐 네이버에서 FE 개발하게 된...
 
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
200820 NAVER TECH CONCERT 13_네이버에서 오픈 소스 개발을 통해 성장하는 방법
 
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
200820 NAVER TECH CONCERT 12_상반기 네이버 인턴을 돌아보며
 
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
200820 NAVER TECH CONCERT 11_빠르게 성장하는 슈퍼루키로 거듭나기
 
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
200819 NAVER TECH CONCERT 07_신입 iOS 개발자 개발업무 적응기
 
200819 NAVER TECH CONCERT 06_놓치기 쉬운 안드로이드 UI 디테일 살펴보기
200819 NAVER TECH CONCERT 06_놓치기 쉬운 안드로이드 UI 디테일 살펴보기200819 NAVER TECH CONCERT 06_놓치기 쉬운 안드로이드 UI 디테일 살펴보기
200819 NAVER TECH CONCERT 06_놓치기 쉬운 안드로이드 UI 디테일 살펴보기
 

Recently uploaded

"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????blackmambaettijean
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 

Recently uploaded (20)

"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 

200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드

  • 1.
  • 3. Android 11 AsyncTask deprecated “Kotlin Coroutines”
  • 6. Direct Style fun loadItem(params: Params) { val token = requestToken() val item = requestItem(token, params) showItem(item) }
  • 7. Direct Style fun loadItem(params: Params) { val token = requestToken() val item = requestItem(token, params) showItem(item) }
  • 8. Direct Style fun loadItem(params: Params) { val token = requestToken() val item = requestItem(token, params) showItem(item) } Continuation
  • 9. onDraw() onDraw() onDraw() Direct Style fun loadItem(params: Params) { val token = requestToken() val item = requestItem(token, params) showItem(item) } UI Thread
  • 10. Continuation-Passing Style (CPS) fun loadItem(params: Params) { requestToken { token -> val item = requestItem(token, params) showItem(item) } }
  • 11. Continuation-Passing Style (CPS) fun loadItem(params: Params) { requestToken { token -> val item = requestItem(token, params) showItem(item) } }
  • 12. Continuation-Passing Style (CPS) fun loadItem(params: Params) { requestToken { token -> val item = requestItem(token, params) showItem(item) } } Continuation Callback!
  • 13. Continuation-Passing Style (CPS) fun loadItem(params: Params) { requestToken { token -> requestItem(token, params) { item -> showItem(item) } } }
  • 14. Coroutines Direct Style suspend fun loadItem(params: Params) { val token = requestToken() val item = requestItem(token, params) showItem(item) }
  • 15. Coroutines Direct Style suspend fun loadItem(params: Params) { val token = requestToken() val item = requestItem(token, params) showItem(item) } onDraw() onDraw() UI Thread suspend resume
  • 16. Coroutines Direct Style suspend fun loadItem(params: Params) { val token = requestToken() val item = requestItem(token, params) showItem(item) } onDraw() onDraw() UI Thread suspend resume
  • 17. Coroutines Direct Style suspend fun loadItem(params: Params) { val token = requestToken() val item = requestItem(token, params) showItem(item) }
  • 19. CPS Transformation suspend fun requestItem(token: Token, params: Params): Item { ... } // Decompile bytecode in Java Object requestItem( Token token, Params params, Continuation<Item> cont ) { ... }
  • 20. CPS Transformation suspend fun requestItem(token: Token, params: Params): Item { ... } // Decompile bytecode in Java Object requestItem( Token token, Params params, Continuation<Item> cont ) { ... }
  • 21. CPS Transformation interface Continuation<in T> { val context: CoroutineContext fun resumeWith(result: Result<T>) }
  • 22. CPS Transformation interface Continuation<in T> { val context: CoroutineContext fun resumeWith(result: Result<T>) }
  • 23. CPS Transformation suspend fun loadItem(params: Params) { val token = requestToken() val item = requestItem(token, params) showItem(item) }
  • 24. CPS Transformation suspend fun loadItem(params: Params) { val token = requestToken() val item = requestItem(token, params) showItem(item) } Initial Continuation
  • 25. CPS Transformation suspend fun loadItem(params: Params) { val token = requestToken() val item = requestItem(token, params) showItem(item) } Continuation
  • 26. CPS Transformation suspend fun loadItem(params: Params) { val token = requestToken() val item = requestItem(token, params) showItem(item) } Continuation
  • 27. Callback ??? fun loadItem(params: Params) { requestToken { token -> requestItem(token, params) { item -> showItem(item) } } }
  • 28. CPS Transformation suspend fun loadItem(params: Params) { // LABEL 0 val token = requestToken() // LABEL 1 val item = requestItem(token, params) // LABEL 2 showItem(item) }
  • 29. CPS Transformation suspend fun loadItem(params: Params) { val sm = object : ContinuationImpl { ... } when (sm.label) { 0 -> val token = requestToken() 1 -> val item = requestItem(token, params) 2 -> showItem(item) } }
  • 30. CPS Transformation suspend fun loadItem(params: Params) { val sm = object : ContinuationImpl { ... } when (sm.label) { 0 -> val token = requestToken() 1 -> val item = requestItem(token, params) 2 -> showItem(item) } } State Machine
  • 31. CPS Transformation fun loadItem(params: Params, cont: Continuation) { val sm = object : ContinuationImpl { ... } when (sm.label) { 0 -> requestToken(sm) 1 -> requestItem(token, params, sm) 2 -> showItem(item) } }
  • 32. CPS Transformation fun loadItem(params: Params, cont: Continuation) { val sm = object : ContinuationImpl { ... } when (sm.label) { 0 -> { sm.params = params sm.label = 1 requestToken(sm) } 1 -> requestItem(token, params, sm) 2 -> showItem(item) } }
  • 33. CPS Transformation fun loadItem(params: Params, cont: Continuation) { val sm = object : ContinuationImpl { ... } when (sm.label) { 0 -> { sm.params = params sm.label = 1 requestToken(sm) } 1 -> requestItem(token, params, sm) 2 -> showItem(item) } }
  • 34. CPS Transformation fun loadItem(params: Params, cont: Continuation) { val sm = object : ContinuationImpl { ... } when (sm.label) { 0 -> { sm.params = params sm.label = 1 requestToken(sm) } 1 -> requestItem(token, params, sm) 2 -> showItem(item) } } State Machine Continuation
  • 35. CPS Transformation fun loadItem(params: Params, cont: Continuation) { val sm = cont as? ThisSM ?: object : ThisSM { fun resumeWith(...) { loadItem(null, this) { } } ... }
  • 36. CPS Transformation fun loadItem(params: Params, cont: Continuation) { val sm = ... when (sm.label) { 0 -> { ... } 1 -> { val params = sm.params val token = sm.result as Token sm.label = 2 requestItem(token, params, sm) } 2 -> { ... } } }
  • 37. CPS Transformation fun loadItem(params: Params, cont: Continuation) { val sm = ... when (sm.label) { 0 -> { ... } 1 -> { val params = sm.params val token = sm.result as Token sm.label = 2 requestItem(token, params, sm) } 2 -> { ... } } }
  • 38. CPS Transformation fun loadItem(params: Params, cont: Continuation) { val sm = ... when (sm.label) { 0 -> { ... } 1 -> { val params = sm.params val token = sm.result as Token sm.label = 2 requestItem(token, params, sm) } 2 -> { ... } } }
  • 39. State Machine vs. Callback •State Machine 은 상태를 저장한 하나의 객체를 공유하지만, Callback 은 매번 closure를 생성해야 함 •복잡한 구조에 대응하기 쉬움 suspend fun loadItems(params: List<Params>) { for (p in params) { val token = requestToken() val item = requestItem(token, p) showItem(item) } }
  • 41. Why Coroutines ? • Structured concurrency ➡ 구조화된 동시성 처리로 memory leak 방지
  • 42. Structured Concurrency @CheckReturnValue @BackpressureSupport(BackpressureKind.UNBOUNDED_IN) @SchedulerSupport(SchedulerSupport.NONE) public final Disposable subscribe(Consumer<? super T> onNext) { return subscribe(onNext, Functions.ON_ERROR_MISSING, Functions.EMPTY_ACTION, FlowableInternalHelper.RequestMax.INSTANCE); }
  • 43. Structured Concurrency fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job { ... } • RxJava leak warn • CoroutineScope leak
  • 44. Why Coroutines ? • Structured concurrency ➡ 구조화된 동시성 처리로 memory leak 방지 • Light weight ➡ 싱글 스레드에서 여러 코루틴을 동시에 실행할 수 있음 (동시성)
  • 45. Kotlin Flow: Reactive scrabble benchmarks •Java 8 Stream - RxJava 간 성능 비교를 위해 José Paumard 에 의해 개발됨 •Rx 관련 코드는 David Karnok 가 작성 https://github.com/Kotlin/kotlinx.coroutines/tree/master/benchmarks/src/jmh/kotlin/benchmarks/flow/scrabble
  • 46. Why Coroutines ? • Structured concurrency ➡ 구조화된 동시성 처리로 memory leak 방지 • Light weight ➡ 싱글 스레드에서 여러 코루틴을 동시에 실행할 수 있음 (동시성) • Built-in cancellation ➡ 계층 구조를 따라 취소가 자동으로 전파됨 • Simplify asynchronous code ➡ 비동기 코드를 콜백 대신 순차적(sequential)인 코드로 작성할 수 있음 ➡ 다양한 Jetpack 라이브러리에서 extensions 등의 형태로 코루틴을 지원
  • 48. , CoroutineScope interface CoroutineScope { val coroutineContext: CoroutineContext } •새로운 코루틴을 시작하는 코루틴 빌더는 모두 CoroutineScope 의 extensions function 으로 구성
  • 49. , launch() & async() fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job { ... } fun <T> CoroutineScope.async( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T ): Deferred<T> { ... }
  • 50. launch() vs. async() • • CoroutineScope • suspend function Exception .await() Exception X launch() async()
  • 51. launch() val job = launch { delay(1000) doSomething() }
  • 52. async() private suspend fun mergeApi(): List<Item> = coroutineScope { val deferredOne = async { fetchApiOne() } val deferredTwo = async { fetchApiTwo() } return deferredOne.await() + deferredTwo.await() }
  • 53. private suspend fun mergeApi(): List<Item> = coroutineScope { val deferredOne = async { fetchApiOne() } val deferredTwo = async { fetchApiTwo() } return deferredOne.await() + deferredTwo.await() } async() fetchApiOne() , fetchApiTwo()
  • 54. async() private suspend fun mergeApi(): List<Item> = coroutineScope { val deferredOne = async { fetchApiOne() } val deferredTwo = async { fetchApiTwo() } return deferredOne.await() + deferredTwo.await() } suspend
  • 55. GlobalScope object GlobalScope : CoroutineScope { override val coroutineContext: CoroutineContext get() = EmptyCoroutineContext } •앱 전체 생명주기로 동작하는 top-level CoroutineScope •대부분의 경우에 사용하면 안됨
  • 56. GlobalScope fun ReceiveChannel<Int>.sqrt(): ReceiveChannel<Double> = GlobalScope.produce(Dispatchers.Unconfined) { for (number in this) { send(Math.sqrt(number)) } }
  • 59. Kotlin Property Delegates for ViewModels class AwesomeFragment : Fragment() { private val model: AwesomeViewModel by viewModels() }
  • 60. Kotlin Property Delegates for ViewModels class AwesomeFragment : Fragment() { private val model: AwesomeViewModel by viewModels() private fun showChildFragment() = childFragmentManager.commit { replace(R.id.fragment_child, ChildFragment()) } } class ChildFragment : Fragment() { ... }
  • 61. Kotlin Property Delegates for ViewModels class AwesomeFragment : Fragment() { private val model: AwesomeViewModel by viewModels() private fun showChildFragment() = childFragmentManager.commit { replace(R.id.fragment_child, ChildFragment()) } } class ChildFragment : Fragment() { private val model: AwesomeViewModel by viewModels({ requireParentFragment() }) }
  • 62. Kotlin Property Delegates for ViewModels class AwesomeFragment : Fragment() { private val model: AwesomeViewModel by viewModels() private fun showChildFragment() = childFragmentManager.commit { replace(R.id.fragment_child, ChildFragment()) } } class ChildFragment : Fragment() { private val model: AwesomeViewModel by viewModels({ requireParentFragment() }) }
  • 63. Kotlin Property Delegates for ViewModels class AwesomeActivity : AppCompatActivity() { private val sharedModel: SharedViewModel by viewModels() } class AwesomeFragment : Fragment() { private val sharedModel: SharedViewModel by activityViewModels() } class ChildFragment : Fragment() { private val sharedModel: SharedViewModel by activityViewModels() }
  • 64. Kotlin Property Delegates for ViewModels class AwesomeActivity : AppCompatActivity() { private val sharedModel: SharedViewModel by viewModels() } class AwesomeFragment : Fragment() { private val sharedModel: SharedViewModel by activityViewModels() } class ChildFragment : Fragment() { private val sharedModel: SharedViewModel by activityViewModels() }
  • 65. CoroutineScope ViewModel class AwesomeViewModel : ViewModel(), CoroutineScope { override val coroutineContext: CoroutineContext get() = EmptyCoroutineContext }
  • 66. Context class AwesomeViewModel : ViewModel(), CoroutineScope { override val coroutineContext: CoroutineContext get() = EmptyCoroutineContext }
  • 68. CoroutineContext • Job ➡ Lifecycle • CoroutineDispatcher ➡ Threading • CoroutineExceptionHandler • CoroutineName
  • 69. CoroutineContext’s Default • Job ➡ No parent job • CoroutineDispatcher ➡ Dispatchers.Default • CoroutineExceptionHandler ➡ None • CoroutineName ➡ “coroutine” context
  • 70. CoroutineContext public interface CoroutineContext { public operator fun <E : Element> get(key: Key<E>): E? public fun <R> fold(initial: R, operation: (R, Element) -> R): R public operator fun plus(context: CoroutineContext): CoroutineContext = ... public fun minusKey(key: Key<*>): CoroutineContext public interface Key<E : Element> public interface Element : CoroutineContext { ... } }
  • 71. CoroutineContext public interface CoroutineContext { public operator fun <E : Element> get(key: Key<E>): E? public fun <R> fold(initial: R, operation: (R, Element) -> R): R public operator fun plus(context: CoroutineContext): CoroutineContext = ... public fun minusKey(key: Key<*>): CoroutineContext public interface Key<E : Element> public interface Element : CoroutineContext { ... } }
  • 72. CoroutineContext public interface CoroutineContext { public operator fun <E : Element> get(key: Key<E>): E? public fun <R> fold(initial: R, operation: (R, Element) -> R): R public operator fun plus(context: CoroutineContext): CoroutineContext = ... public fun minusKey(key: Key<*>): CoroutineContext public interface Key<E : Element> public interface Element : CoroutineContext { ... } }
  • 73. CoroutineContext public interface CoroutineContext { public operator fun <E : Element> get(key: Key<E>): E? public fun <R> fold(initial: R, operation: (R, Element) -> R): R public operator fun plus(context: CoroutineContext): CoroutineContext = ... public fun minusKey(key: Key<*>): CoroutineContext public interface Key<E : Element> public interface Element : CoroutineContext { ... } }
  • 74. CoroutineContext public interface CoroutineContext { public operator fun <E : Element> get(key: Key<E>): E? public fun <R> fold(initial: R, operation: (R, Element) -> R): R public operator fun plus(context: CoroutineContext): CoroutineContext = ... public fun minusKey(key: Key<*>): CoroutineContext public interface Key<E : Element> public interface Element : CoroutineContext { ... } }
  • 75. CoroutineContext public interface CoroutineContext { public operator fun <E : Element> get(key: Key<E>): E? public fun <R> fold(initial: R, operation: (R, Element) -> R): R public operator fun plus(context: CoroutineContext): CoroutineContext = ... public fun minusKey(key: Key<*>): CoroutineContext public interface Key<E : Element> public interface Element : CoroutineContext { ... } }
  • 76. CoroutineContext public interface CoroutineContext { public operator fun <E : Element> get(key: Key<E>): E? public fun <R> fold(initial: R, operation: (R, Element) -> R): R public operator fun plus(context: CoroutineContext): CoroutineContext = ... public fun minusKey(key: Key<*>): CoroutineContext public interface Key<E : Element> public interface Element : CoroutineContext { ... } }
  • 77. CoroutineContext public interface CoroutineContext { public operator fun <E : Element> get(key: Key<E>): E? public fun <R> fold(initial: R, operation: (R, Element) -> R): R public operator fun plus(context: CoroutineContext): CoroutineContext = ... public fun minusKey(key: Key<*>): CoroutineContext public interface Key<E : Element> public interface Element : CoroutineContext { ... } } coroutineContext[Job]
  • 78. CoroutineContext public interface CoroutineContext { public operator fun <E : Element> get(key: Key<E>): E? public fun <R> fold(initial: R, operation: (R, Element) -> R): R public operator fun plus(context: CoroutineContext): CoroutineContext = ... public fun minusKey(key: Key<*>): CoroutineContext public interface Key<E : Element> public interface Element : CoroutineContext { ... } } Job() + Dispathchers.IO
  • 79. Job • (Lifecycle) wait children +-----+ start +--------+ complete +-------------+ finish +-----------+ | New | -----> | Active | ---------> | Completing | -------> | Completed | +-----+ +--------+ +-------------+ +-----------+ | cancel / fail | | +----------------+ | | V V +------------+ finish +-----------+ | Cancelling | --------------------------------> | Cancelled | +------------+ +-----------+
  • 80. Job • (Hierarchy) Parent Job Child Job Child Job Child Job Child Job
  • 81. Job class AwesomeViewModel : ViewModel(), CoroutineScope { private val job = Job() override val coroutineContext: CoroutineContext get() = job override fun onCleared() { super.onCleared() job.cancel() } } •When a child fails, it propagates cancellation to other children •When a failure is notified, the scope propagates the exception up
  • 82. SupervisorJob class AwesomeViewModel : ViewModel(), CoroutineScope { private val job = SupervisorJob() override val coroutineContext: CoroutineContext get() = job override fun onCleared() { super.onCleared() job.cancel() } } •The failure of a child doesn't affect other children •When a failure is notified, the scope doesn't do anything
  • 83. Cooperative cancellation repeat (5) { someBlockingTask() } repeat (5) { yield() // or ensureActive() someBlockingTask() }
  • 84. Cooperative cancellation while (true) { someBlockingTask() } while (isActive) { someBlockingTask() }
  • 85. Dispatchers actual object Dispatchers { @JvmStatic actual val Default: CoroutineDispatcher = createDefaultDispatcher() @JvmStatic actual val Main: MainCoroutineDispatcher get() = MainDispatcherLoader.dispatcher @JvmStatic actual val Unconfined: CoroutineDispatcher = kotlinx.coroutines.Unconfined @JvmStatic val IO: CoroutineDispatcher = DefaultScheduler.IO }
  • 86. Main-safe suspend function suspend fun mainSafeFunc() { val result = withContext(Dispatchers.IO) { fetchApi() } return result.name } • Main(UI) Thread suspend function withContext ➡ e.g. Retrofit 2.6.0+ suspend function
  • 87. Job + Dispatchers class AwesomeViewModel : ViewModel(), CoroutineScope { private val job = SupervisorJob() override val coroutineContext: CoroutineContext get() = job + Dispatchers.Main override fun onCleared() { super.onCleared() job.cancel() } }
  • 88. class AwesomeViewModel : ViewModel(), CoroutineScope { private val job = SupervisorJob() override val coroutineContext: CoroutineContext get() = job + Dispatchers.Main init { launch { // Call suspend func. } } override fun onCleared() { super.onCleared() job.cancel() } }
  • 89. Lifecycle-aware coroutine scopes •For ViewModelScope, use androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0-beta01 or higher. class PlainViewModel : ViewModel() { init { viewModelScope.launch { // Call suspend func. } } }
  • 90. Lifecycle-aware coroutine scopes •For LifecycleScope, use androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha01 or higher. // Activity or Fragment class PlainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycleScope.launch { // Call suspend func. } lifecycleScope.launchWhenResumed { // Call suspend func. } } }
  • 93. ViewModel + LiveData class PlainViewModel : ViewModel() { private val _result = MutableLiveData<String>() val result: LiveData<String> = _result init { viewModelScope.launch { val computationResult = doComputation() _result.value = computationResult } } }
  • 94. LiveData Builder •For liveData, use androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01 or higher. class PlainViewModel : ViewModel() { val result: LiveData { emit(doComputation()) } }
  • 95. LiveData Builder class PlainViewModel : ViewModel() { // itemId item private val itemId = MutableLiveData<String>() val result = itemId.switchMap { liveData { emit(fetchItem(it)) } } // LiveData val weather = liveData(Dispatchers.IO) { emit(LOADING_STRING) emitSource(dataSource.fetchWeather()) // LiveData } }
  • 96. StateFlow • LiveData State holder ! • state StateFlow interface StateFlow<T> : Flow<T> { val value: T // always available, reading it never fails } interface MutableStateFlow<T> : StateFlow<T> { override var value: T // can read & write value } fun <T> MutableStateFlow(value: T): MutableStateFlow<T> // constructor fun
  • 99. Paging 2 class AwesomeDataSource(parent: Job? = null) : PositionalDataSource<Awesome>(), CoroutineScope { private val job = SupervisorJob(parent) override val coroutineContext: CoroutineContext get() = Dispatchers.Unconfined + job override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback<Awesome>) { launch { runCatching { loadInternal(params.requestedStartPosition, params.requestedLoadSize) } .fold( onSuccess = { callback.onResult(it, params.requestedStartPosition) }, onFailure = { callback.onResult(emptyList(), params.requestedStartPosition) } ) } } ... }
  • 100. Paging 3 •First-class support for Kotlin coroutines and Flow, as well as LiveData and RxJava. •현재 알파 버전 (3.0.0-alpha04)
  • 101. Paging 3 @ExperimentalPagingApi abstract class RemoteMediator<Key : Any, Value : Any> { abstract suspend fun load(loadType: LoadType, state: PagingState<Key, Value>): MediatorResult ... }
  • 108. RxJava - Coroutines // Coroutines -> Rx val single = rxSingle { // call suspend func. } // Rx -> Coroutines val result = single.await()
  • 109. Coroutines suspend fun request(id: String): Awesome = suspendCancellableCoroutine { cont -> cont.invokeOnCancellation { // Cancel execution. } awesomeModelProvider .request(id) .execute(object : Response { override fun onSuccess(items: Awesome) { cont.resume(items) } override fun onError(message: String?) { cont.resumeWithException(IOException(message)) } }) } launch { textView.text = request(id).name }