| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
- Coroutines
- 추상 팩토리
- 팩토리 메소드
- Kotlin
- 빌터패턴
- 옵저버 패턴
- 디자인패턴
- 코루틴
- android designsystem
- 안드로이드 디자인시스템
- 프로토타입 패턴
- ㅋㅁ
- factory method
- 코틀린멀티플랫폼
- 디자인패턴 #
- Abstract Factory
- compose
- kotlin multiplatform
- 추상팩토리패턴
- builderPattern
- Observer Pattern
- 코틀린
- 함수형프로그래밍
- PrototypePattern
- Functional Programming
- Design Pattern
- define
- designPattern
- kmp
- material3
- Today
- Total
오늘도 더 나은 코드를 작성하였습니까?
1장 코틀린 코루틴을 배워야 하는 이유 본문
아래와 같은 데이터 처리 과정이 있다고 가정해보자.
fun onCreate() {
val news = getNewsFromApi()
val sortedNews = news.sortedByDescending { it.publishedAt }
view.showNews(sortedNews)
}
1. api를 통해서 news 데이터를 받아온다.
2. 발행순서대로 정렬한다.
3. 뷰를 통해 보여준다.
안드로이드에서는 하나의 앱에서 뷰를 다루는 스레드가 단 하나만 존재한다.
- MainThread (UiThread)라 부른다.
- 앱에서 가장 중요한 스레드로 절대로 블로킹 되어선 안된다.
- 블로킹 된다면, 앱 크래시가 발생(비정상 종료)
즉, 위의 코드는 정상 val news = getNewsFromApi() 함수가 결과를 받을때 까지 mainThread는 블로킹 되고, 앱크래시가 발생한다.
getNewsFromApi()를 다른 스레드에서 부르더라도, 정렬과 보여줄 데이터가 없기 때문에 앱크래시가 발생한다.
스레드 전환
과거 안드로이드에서 쓰던 방식들... runOnUiThread, Hander, AsyncTask등...
fun onCreate() {
thread {
val news = getNewsFromApi()
val sortedNews = news.sortedByDescending { it.publishedAt }
runOnUiThread {
view.showNews(sortedNews)
}
}
}
1. 블로킹을 해도 되는 스레드로 코드를 실행한다.
2. api 요청 및 정렬 작업 완료.
3. UiThread로 전환하여 데이터를 보여준다.
문제점
- 스레드가 실행되었을때, 멈출 수 있는 방법이 없어 메모리 누수발생
- 스레드를 생성하면 비용이 많이듦.
- 스레드 컨텍스트 스위칭을 통해 오버헤드 비용이 들어감.
- 코드가 쓸데없이 길어지고, 직관적이지 못해서 이해력이 떨어짐.
콜백
함수를 논블로킹으로 실행 시키고, 함수의 작업이 종료 되었을때, 호출될 콜백 함수를 넘겨주는 방식.
fun onCreate() {
getNewsFromApi { news ->
val sortedNews = news.sortedByDescending { it.publishedAt }
view.showNews(sortedNews)
}
}
문제점
- 중간에 작업을 멈추거나 취소할 수 있는 방법이 없음.
- 여러 Api를 동시에 호출해서 데이터를 받아오는 경우라면, 병렬처리가 쉽지 않음.
- 순차적으로 Api를 호출하는 경우에 콜백지옥 발생.
Rxjava와 리액티브 스트림
Rxjava 또는 리액티브 스트림은 데이터를 스트림의 형태로 생성, 처리, 관찰을 할수 있다.
fun onCreate() {
disposables += getNewsFromApi()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map { news ->
news.sortedByDescending { it.publishedAt }
}
.subscribe { sortedNews ->
view.showNews(sortedNews)
}
}
병렬성 처리.
fun showNews() {
disposable += Observable.zip(
getConfigFromApi().flatMap{ getNewsApi(it) },
getUserFromApi(),
Function2 { news: List<News>, config: Config ->
Pair(new, config)
})
.subScribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subScribe{ (news, config) ->
view.showNews(news, config)
}
}
문제점
- RxOOO을 배워야함.
- 병렬성 처리를 할수 있지만, 코드가 복잡함.
Kotlin Coroutine의 사용.
fun onCreate() {
viewModelScope.launch { // 코루틴 생성
val news = getNewsFromApi() // 메인스레드를 할당 받은 코루틴이 api 호출 후 중단, MainThread는 다른 일을함.
val sortedNews = news.sortedByDescending { it.publishedAt }
view.showNews(sortedNews)
}
}
- UiThread를 블로킹 하는 대신에, 코루틴을 중단 시킴.
- 데이터를 받은 이후 코루틴이 중단된 이후 부터 작업을 재개함.
병렬성 처리
fun onCreate() {
viewModelScope.launch {
val config = async { getConfigFromApi() }
val news = async { getNewsFromApi(config) }
val user = async { getUserFromApi() }
view.showNews(user.await(), news.await())
}
}
- 코드가 간결하고 이해하기 쉬움.
- 병렬처리 또한 async, await 패턴을 사용하여 쉽게처리.
- 코틀린의 다른 라이브러리 와 통합되어서 사용됨.