오늘은 Festago 출시 후 앱에 crash 가 발생한 첫 번째 사례와 해결한 방법에 대해 써보겠습니다. 문제 발생 과정 개발 과정에서는 문제가 생기지 않았고 처음 설치했을 때도 문제가 발생하지 않았다. 첫 출시에 감격하고 있었는데.. 곧바로 문제가 발생했다. 앱을 삭제했다가 다시 설치하면 무조건 crash 가 발생하는 것이다! 전혀 예상치 못한 오류에 어디서 문제가 발생한건지 왜 두 번 설치해야 문제가 발생하는 것인지 고민하다가 프로젝트에 적용한 Firebase Crashlytics Log를 확인해보았다. AuthLocalDataSource 의 SharedPreferences 에서 오류가 발생한 것이었다. 오류 메세지는 다음과 같았다. Caused by android.security.KeyStoreE..
전체 글
이 글은 Kotlin Coroutines : Deep Dive 책 내용을 다루고 있습니다. 들어가기 전에 공식문서나 책을 읽다보면 이런 얘기가 많이 나온다. List, Set 과 같은 컬렉션은 Hot, Sequence 와 자바의 Stream 은 Cold 이다. Channel 은 Hot 이지만 Flow, RxJava 스트림(observable, Single) 은 Cold 이다. 도대체 뭐가 뜨겁고 뭐가 차가운걸까..? 오늘은 데이터 소스의 두 가지 종류 Hot 데이터 스트림과 Cold 데이터 스트림의 차이를 확실히 이해해보자. Hot vs Cold Hot 데이터 스트림은 열정적이라 데이터를 소비하는 것과 무관하게 원소를 생성한다. Cold 데이터 스트림은 게을러서 요청이 있을 때만 작업을 수행하며 아무것도..
이 글은 Kotlin Coroutines : Deep Dive 책 내용을 다루고 있습니다. 자동차를 탈 때 내부 구조를 알 필요는 없다. 다만 이해도를 높여줄 수 있다. 한 번에 이해하기에 내용이 어려워서 그냥 이런게 있구나 하고 가볍게 넘어가려고 한다. 들어가기 전에 이 책에서는 코루틴 실제 구현에 대해 다음과 같이 중요한 점을 얘기한다. 중단 함수(suspend function)가 시작할 때, 호출되었을 때, 상태를 가진다는 점에서 상태 머신과 비슷하다. Continuation 객체는 상태를 나타내는 숫자와 로컬 데이터를 가진다. 함수의 Continuation 객체가 이 함수를 부르는 다른 함수의 Continuation 객체를 장식(decorate)한다. 그 결과 모든 Continuation 객체는 ..
그동안 당연하게 써 온 Repository 패턴인데 이론적으로 잘못 이해하고 있었다. 추상화해서 갈아끼우기 좋은 구조로 만들고 계층간 분리하는 것까지 Repository 패턴인 줄 알았는데 아니었다. 따라서 오늘은 안드로이드 공식문서에서 말하는 Repository 패턴에 대해서 확실히 알고 넘어가자. Repository 저장소 패턴은 데이터 레이어를 앱의 나머지 부분에서 분리하는 디자인 패턴 이다. 데이터 레이어는 UI 와는 별도로 앱의 데이터와 비즈니스 로직을 처리하는 부분이다. Repository 는 앱의 나머지 layer 에서 이 데이터에 액세스할 수 있도록 일관된 API를 노출한다. 데이터 레이어에는 네트워킹 코드, Room 데이터베이스, 오류 처리, 데이터를 읽거나 조작하는 코드 등이 포함. 즉..
테스트, 아키텍처, 다 중요하지만 간과하는 부분이 있었다. 안드로이드 개발자라면 요구사항에 맞는 View 를 마음껏 그려내고 지연을 줄여 최적화 할 수 있어야한다. 오늘은 뷰가 그려지는 과정에 대해 이해해보자. View Lifecycle https://proandroiddev.com/the-life-cycle-of-a-view-in-android-6a2c4665b95e https://medium.com/android-deep-dive-study/introduce-android-ui-rendering-principle-and-view-optimization-1-f593820c7a50 Custom View 를 만들다보면 View Lifecycle 를 마주할 때가 있다. View Lifecycle 에 대해 알..
삶의 의미 많은 사람들이 한 번쯤 생각해 볼 것이다. 어차피 죽을 건데 왜 사냐고. 인간은 우주의 먼지 같은 존재라고 과거의 나는 이 숨막힐 듯 거대한 무의미에 짓눌려 허덕였다. 그럼에도 작지만 빛나는 의미 하나를 찾고 싶었다. “삶의 의미는 무엇인가요?” 그 누구도 쉽게 답하지 못했지만 각자 경험을 토대로 서로 다른 답을 들려주었다. 그제야 삶의 의미를 알게 됐다. 나만의 의미를 찾아가는 그 삶이 자체가 의미 있는 것이라고 그때부터 결과가 아닌 과정, 삶 자체에 집중하기 시작했다. “정답이 없으면 결과보다 과정이 중요하다.” 삶과 개발 개발에는 정답이 없다. 다수의 의견도 있고 누군가의 경험에 의해 정형화된 방법(아키텍처나 패턴 등)도 있다. 그렇지만 그것조차 정답은 아니다. 몹프로그래밍이나 팀프로젝트..
벌써 우아한테크코스 레벨 4! 배우면 배울수록 배워야 할 것도 많아지고 기억해야 할 것도 많아지는 기분이다. 레벨 3에선 팀 프로젝트 진행을 위해 미션이 사라졌었다. 레벨 4엔 "심화 미션" 이라는 이름으로 다시 미션이 돌아왔고 더 깊은 공부를 할 수 있게 되었다. 그 첫 번째는 “자동 DI 구현하기” Dagger Hilt 나 Koin 을 제대로 사용해본 적 없이 수동 DI 만 구현해본 나에게 자동 DI 가 무슨 말인지 이해조차 되지 않았다. 그래서 처음엔 수동 DI 부터 만들어 보았다. private val viewModelFactory = object : ViewModelProvider.Factory { override fun create(modelClass: Class): T { return whe..
Festago 를 개발하면서 ViewModel 의 UiState 및 Event 를 감지하기 위해 LiveData 를 사용했다. 이상적으로 ViewModel 은 Android 를 알아선 안된다. 테스트 가능성, 메모리 누수 안전성, 모듈성을 향상시킨다. 참고: AndroidDevelopers 블로그 https://medium.com/androiddevelopers/viewmodels-and-livedata-patterns-antipatterns-21efaef74a54 이를 이유로 안드로이드 의존성을 갖는 LiveData 를 사용하던 기존 코드들을 Kotlin 의존성을 갖는 Flow 로 Migration 해보기로 했다. StateFlow 와 SharedFlow 에 대한 이론적인 글은 다음 글을 참고해주세요...
자동 DI 블로그 글을 쓰다가 리플렉션에 대한 정리를 먼저 하고 넘어가는게 좋다고 판단되어 주제로 선정하였다. 자동 DI 를 구현하려면 리플렉션을 먼저 알아야한다. Reflection 이 뭐지? kotlin in Action 에 따르면 실행 시점에 동적으로 객체의 프로퍼티와 메서드에 접근할 수 있게 해주는 방법이다. 이는 성능을 떨어뜨리며 객체지향을 무시해버리기 때문에 개발할 때 보통 사용하지 않는 방법이다. (아래 사용 방법을 보면 이해할 것이다.) 하지만 라이브러리 등을 구현하려면 꼭 필요한 경우도 존재한다. 코틀린에서는 두 가지 서로 다른 Reflection API 를 사용할 수 있는데 자바 Reflection, 코틀린 Reflection 이 있다. 코틀린 클래스는 자바 바이트코드로 컴파일 되기 때..
안드로이드 테스트 피라미드 피라미드를 올라갈수록 비용 증가, 아래로 내려갈수록 더 많은 테스트가 작성되어야 한다. 안드로이드 테스트를 작성해 봤거나 그렇지 않더라도 두 가지 패키지를 보았을 것이다. androidtest : 실제 또는 가상 디바이스에서 실행할 테스트를 작성한다. JVM 만으로는 검증할 수 없는 테스트가 포함된다. test : 로컬 JVM에서 실행되는 테스트이다. 단위 테스트를 작성한다. 안드로이드 의존성이 있는 테스트는 모두 androidTest 하위에 위치해야 하는걸까? UI 로직을 검증하기 위한 테스트를 단위 테스트로 만들 수는 없을까? Robolectric Robolectric을 사용하면 JVM 내에서 "시뮬레이션된" 안드로이드 환경에서 테스트가 실행된다. 즉, 한마디로 안드로이드 ..