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

Angular 2.0 forms
Angular 2.0 formsAngular 2.0 forms
Angular 2.0 formsEyal Vardi
 
Odoo disaster recovery with barman
Odoo disaster recovery with barmanOdoo disaster recovery with barman
Odoo disaster recovery with barmanOdoo
 
웹 프로그래밍 팀프로젝트 최종발표
웹 프로그래밍 팀프로젝트 최종발표웹 프로그래밍 팀프로젝트 최종발표
웹 프로그래밍 팀프로젝트 최종발표Seong Heum Park
 
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기정민 안
 
Introduction to RxJS
Introduction to RxJSIntroduction to RxJS
Introduction to RxJSBrainhub
 
How to implement internationalization (i18n) in angular application(multiple ...
How to implement internationalization (i18n) in angular application(multiple ...How to implement internationalization (i18n) in angular application(multiple ...
How to implement internationalization (i18n) in angular application(multiple ...Katy Slemon
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized projectFabio Collini
 
Kotlin Coroutines in Practice @ KotlinConf 2018
Kotlin Coroutines in Practice @ KotlinConf 2018Kotlin Coroutines in Practice @ KotlinConf 2018
Kotlin Coroutines in Practice @ KotlinConf 2018Roman Elizarov
 
Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...
Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...
Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...Edureka!
 
Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017Roman Elizarov
 
Angular Advanced Routing
Angular Advanced RoutingAngular Advanced Routing
Angular Advanced RoutingLaurent Duveau
 
제3회 오픈 로보틱스 세미나 (제12세션) : 로봇 암 모델링과 MoveIt! 사용법
제3회 오픈 로보틱스 세미나 (제12세션) : 로봇 암 모델링과 MoveIt! 사용법제3회 오픈 로보틱스 세미나 (제12세션) : 로봇 암 모델링과 MoveIt! 사용법
제3회 오픈 로보틱스 세미나 (제12세션) : 로봇 암 모델링과 MoveIt! 사용법Yoonseok Pyo
 
AngularJS Architecture
AngularJS ArchitectureAngularJS Architecture
AngularJS ArchitectureEyal Vardi
 
Easy tests with Selenide and Easyb
Easy tests with Selenide and EasybEasy tests with Selenide and Easyb
Easy tests with Selenide and EasybIakiv Kramarenko
 
Kotlin 2.0을 통해 알아보는 코틀린의 미래
Kotlin 2.0을 통해 알아보는 코틀린의 미래Kotlin 2.0을 통해 알아보는 코틀린의 미래
Kotlin 2.0을 통해 알아보는 코틀린의 미래Leonardo YongUk Kim
 
[부스트캠퍼세미나]조성동_야_너두_TDD_할_수_있어
[부스트캠퍼세미나]조성동_야_너두_TDD_할_수_있어[부스트캠퍼세미나]조성동_야_너두_TDD_할_수_있어
[부스트캠퍼세미나]조성동_야_너두_TDD_할_수_있어CONNECT FOUNDATION
 
Angular components
Angular componentsAngular components
Angular componentsSultan Ahmed
 

What's hot (20)

Angular 2.0 forms
Angular 2.0 formsAngular 2.0 forms
Angular 2.0 forms
 
Odoo disaster recovery with barman
Odoo disaster recovery with barmanOdoo disaster recovery with barman
Odoo disaster recovery with barman
 
웹 프로그래밍 팀프로젝트 최종발표
웹 프로그래밍 팀프로젝트 최종발표웹 프로그래밍 팀프로젝트 최종발표
웹 프로그래밍 팀프로젝트 최종발표
 
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
 
Introduction to RxJS
Introduction to RxJSIntroduction to RxJS
Introduction to RxJS
 
How to implement internationalization (i18n) in angular application(multiple ...
How to implement internationalization (i18n) in angular application(multiple ...How to implement internationalization (i18n) in angular application(multiple ...
How to implement internationalization (i18n) in angular application(multiple ...
 
Angular Directives
Angular DirectivesAngular Directives
Angular Directives
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized project
 
Kotlin Coroutines in Practice @ KotlinConf 2018
Kotlin Coroutines in Practice @ KotlinConf 2018Kotlin Coroutines in Practice @ KotlinConf 2018
Kotlin Coroutines in Practice @ KotlinConf 2018
 
Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...
Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...
Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...
 
Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017
 
Spring aop
Spring aopSpring aop
Spring aop
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
Angular Advanced Routing
Angular Advanced RoutingAngular Advanced Routing
Angular Advanced Routing
 
제3회 오픈 로보틱스 세미나 (제12세션) : 로봇 암 모델링과 MoveIt! 사용법
제3회 오픈 로보틱스 세미나 (제12세션) : 로봇 암 모델링과 MoveIt! 사용법제3회 오픈 로보틱스 세미나 (제12세션) : 로봇 암 모델링과 MoveIt! 사용법
제3회 오픈 로보틱스 세미나 (제12세션) : 로봇 암 모델링과 MoveIt! 사용법
 
AngularJS Architecture
AngularJS ArchitectureAngularJS Architecture
AngularJS Architecture
 
Easy tests with Selenide and Easyb
Easy tests with Selenide and EasybEasy tests with Selenide and Easyb
Easy tests with Selenide and Easyb
 
Kotlin 2.0을 통해 알아보는 코틀린의 미래
Kotlin 2.0을 통해 알아보는 코틀린의 미래Kotlin 2.0을 통해 알아보는 코틀린의 미래
Kotlin 2.0을 통해 알아보는 코틀린의 미래
 
[부스트캠퍼세미나]조성동_야_너두_TDD_할_수_있어
[부스트캠퍼세미나]조성동_야_너두_TDD_할_수_있어[부스트캠퍼세미나]조성동_야_너두_TDD_할_수_있어
[부스트캠퍼세미나]조성동_야_너두_TDD_할_수_있어
 
Angular components
Angular componentsAngular components
Angular components
 

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

Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017Roman Elizarov
 
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 Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKirill Rozov
 
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
 

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

Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017Deep dive into Coroutines on JVM @ KotlinConf 2017
Deep dive into Coroutines on JVM @ KotlinConf 2017
 
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
 
Kotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is coming
 
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
 

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 04_NDK로 안드로이드에 C++ 끼얹기
200819 NAVER TECH CONCERT 04_NDK로 안드로이드에 C++ 끼얹기200819 NAVER TECH CONCERT 04_NDK로 안드로이드에 C++ 끼얹기
200819 NAVER TECH CONCERT 04_NDK로 안드로이드에 C++ 끼얹기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 04_NDK로 안드로이드에 C++ 끼얹기
200819 NAVER TECH CONCERT 04_NDK로 안드로이드에 C++ 끼얹기200819 NAVER TECH CONCERT 04_NDK로 안드로이드에 C++ 끼얹기
200819 NAVER TECH CONCERT 04_NDK로 안드로이드에 C++ 끼얹기
 

Recently uploaded

AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
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
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 

Recently uploaded (20)

AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
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
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 

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 }