전체 글
[Kotlin] MutableSharedFlow의 tryEmit()이 실행되지 않을 때
SharedFlow는 코루틴에서 쉽게 사용할 수 있는 Hot Stream입니다. 안드로이드에서는 뷰모델에서 이벤트 처리할 때 자주 사용합니다. 이번에 MutableSharedFlow를 사용하며 tryEmit()이 실행되지 않는 이슈가 있었고, 이에 대한 내용을 공유해보고자 합니다. 아래에 예시 코드는 뷰모델에서 특정 이벤트를 발생시켜 액티비티에서 이벤트를 처리해주는 코드입니다. class MainViewModel @Inject constructor() : ViewModel() { private val _event = MutableSharedFlow() val event = _event.asSharedFlow() fun doSomething() { _event.tryEmit(ToastEvent("오류입니다..
[Android] ViewModel에서 실행한 이벤트 기다리기
ViewModel에서 이벤트를 처리하는 방법에는 여러 가지가 있습니다. (참고 : MVVM의 ViewModel에서 이벤트를 처리하는 방법 6가지) 이벤트에는 토스트 띄우기, 다이얼로그 보여주기 등 여러 가지 종류가 있는데요, 그중에는 사용자의 액션이 포함된 이벤트들도 있습니다. 이번 글에서는 ViewModel에서 실행한 이벤트를 기다리는 방법에 대해 알아보겠습니다. 예를 들어, 아래와 같은 동작을 수행하려고 합니다. 사용자가 로그아웃을 하려고 함. 로그아웃 전에 다이얼로그로 "로그아웃을 하시겠습니까?"를 보여줌. 사용자가 OK 버튼을 누르면 로그아웃 처리 후 토스트로 "로그아웃이 되었습니다."를 보여줌. 여기서의 이벤트는 '다이얼로그를 띄운다.', '토스트를 보여준다.' 2가지인데요, 이 중 다이얼로그를..
[Android] Clean Architecture에서 Paging 라이브러리 사용하기 - 도메인 계층의 의존성 문제
이번 글에서는 Clean Architecture에서 Paging 라이브러리를 사용할 경우 의존성을 어떤 식으로 관리해야 할지에 대해 다뤄보겠습니다. 프로젝트 구조 제가 현재 진행 중인 개인 프로젝트는 Clean Architecture + Multi module로 구성되어 있습니다. 위의 사진과 같이 Clean Architecture의 data, domain, presentation 계층에 맞게 총 3개의 모듈로 나누어져 있으며, data -> domain, presentation -> domain의 의존 관계를 가지고 있습니다. 또한 data와 presentation 모듈은 안드로이드 라이브러리로 되어 있고, domain 모듈은 안드로이드에 대한 의존성이 없는 Kotlin 라이브러리 되어 있습니다. Cl..
Amazing circle of numbers 1 to 32
웹서핑을 하다가 신기한 짤을 하나 보게 되었다. 흔히 서울대 애들이 흥분하는 짤이라고 하는데 너무 신기해서 가져와봤다. 간단하게 설명하자면 원에는 1부터 32까지의 수가 중복 없이 들어 있으며, 인접한 두 수를 더하면 제곱수가 된다. 너무 신기하다! 원리가 궁금했다. 그래서 찾아보던 와중 또 신기한 사실을 발견했다. n=32일 때만 우연하게 가능한 줄 알았는데 32 이상의 자연수면 가능하다고 한다. 어떻게 가능한 건지 수학적으로 증명된 것은 찾지 못했지만.. n이 다른 숫자일 때 정말 가능한지, 가능하다면 그 배열이 어떻게 되는지 궁금했다. 자료를 찾다보니 위의 문제는 해밀턴 순환을 찾는 문제와 같다고 해서 직접 구현해보기로 했다. 해밀턴 순환을 찾는 문제는 그래프와 백트래킹 알고리즘을 이용해서 풀 수 ..
[Android] MVVM 패턴과 AAC에서의 ViewModel
안드로이드 오픈 톡방을 보다 보면 주기적으로 올라오는 질문이 몇 가지 있습니다. 그중 하나가 MVVM 패턴에서의 ViewModel과 AAC(Android Architecture Components)에서 제공하는 ViewModel이 다른 것인가에 대한 질문입니다. 앱 개발 시에 MVVM 패턴을 많이 사용하고, AAC에서 ViewModel을 제공하니 두 ViewModel이 같은 개념일 거라고 생각합니다. 결론부터 말해보자면, 두 ViewModel은 전혀 상관이 없습니다. MVVM 패턴에서 ViewModel의 역할과 AAC에서 제공하는 ViewModel의 역할은 개념적으로 차이가 있습니다. 심지어 안드로이드 공식문서에서 ViewModel을 설명할 때 MVVM 패턴에 대한 언급은 전혀 없습니다. 만약 AAC의 ..
[Android] Gson을 이용한 Room에 다양한 타입의 데이터 저장하기
Room은 Android Jetpack에서 제공하는 라이브러리로, SQLite에 대한 추상화 레이어를 제공하여 로컬 데이터베이스를 보다 간단하게 사용할 수 있게 해줍니다. 많은 양의 데이터를 처리하는 앱은 데이터를 로컬로 유지해서 많은 이점을 얻을 수 있습니다. 가장 대표적인 예시로는 데이터를 로컬 디비에 캐싱하는 것입니다. 앱이 네트워크에 접근할 수 없는 오프라인 상태인 경우에도 데이터가 로컬 디비에 저장되어 있다면, 이를 활용하여 콘텐츠를 탐색할 수 있습니다. Room에 데이터를 저장할 때는 기본적으로 primitive type과 그 wrapping 타입만 지원합니다. 그럼 그 외의 사용자가 정의한 커스텀 클래스나 List와 같은 경우는 어떻게 저장해야 할까요? 이번 글에서는 Room에서 다양한 타입..
[Android] 스켈레톤 로딩 화면 구현하기 - Facebook shimmer library
사용자가 어떠한 요청을 했는데 화면에 아무런 변화가 없다면 어떤 느낌을 받을까요? 요청이 제대로 들어갔는지, 앱이 고장 난 건지 사용자는 알 수가 없습니다. 따라서 데이터를 로딩 중에는 사용자가 알기 쉽게 로딩 애니메이션을 보여주는 것이 좋습니다. 로딩 애니메이션에는 스켈레톤 UI, 루프 애니메이션, 프로그래스 바 등의 다양한 방법이 있습니다. 이번 포스팅에서는 위의 화면과 같이 스켈레톤 로딩 화면을 구현해보겠습니다. 스켈레톤 로딩 화면은 표시될 정보의 대략적인 형태를 미리 보여줘서 다음 화면까지 부드럽게 연결해주는 역할을 합니다. 스켈레톤 로딩 화면을 구현하는 데는 여러 방법이 있지만, 가장 유명한 Facebook에서 제공하는 shimmer-android 라이브러리를 사용해보겠습니다. 라이브러리 추가 ..
[Android] viewModelScope.launch() 간단하게 바꿔보기
ViewModel에서 코루틴을 사용할 때는 androidx-lifecycle에서 제공하는 viewModelScope를 많이 사용합니다. viewModelScope는 ViewModel의 extension property로 ViewModel이 destroy 될 때 자식 코루틴들을 자동으로 취소하는 기능을 제공합니다. 이번 포스팅에서는 viewModelScope를 보다 간단하게 사용할 수 있는 방법을 알아보겠습니다. 확장 함수 사용하여 개선하기 ViewModel에서 viewModelScope을 사용해 코루틴을 실행할 때는 일반적으로 아래와 같은 방식으로 사용합니다. class MainViewModel : ViewModel() { init { viewModelScope.launch { // ... } viewM..