💡DI 패턴을 사용하는 이유안드로이드 진영에서 DI 패턴은 필수적으로 사용되는 디자인 패턴 중 하나이다.여기서 개발자들은 Dagger, Hilt, Koin와 같은 DI 툴들을 선택해서 도입하게 되는데, 난 첫 DI 라이브러리로 Hilt를 사용했고 아직까지도 Hilt만 사용해오고 있다. 모든 디자인 패턴이 그렇듯, DI 패턴은 결합도 감소, 테스트 용이성 향상, 유지보수성 증가, 보일러플레이트 감소를 목적으로 사용된다. 내 생각에 DI 패턴만큼 테스트 용이성 향상과 결합도 감소에 효과적인 디자인 패턴은 없다. 게다가 안드로이드처럼 프레임워크 클래스들의 생명주기를 신경써야 하는 환경에서 Hilt나 Dagger를 사용한 DI 패턴은 더더욱 중요하다. 객체를 생성/파괴하는 로직을 라이브러리 레벨에서 처리해주기..
JVM의 GC는 heap 영역의 객체들 중에서 가비지(더 이상 참조되지 않는 객체)를 찾아 처리함으로써 할당했던 메모리를 회수하는 역할을 한다.하지만 GC는 메모리 관리의 일관성과 안정성을 보장하기 위해 외부의 영향을 최대한 제한하는 구조로 설계되어, java.lang.ref 패키지의 참조 객체 관련 요소들로만 GC에 제한적으로 어필이 가능하다.기본적인 참조 방식인 "강한 참조"는 별도의 클래스로 제공되지 않으며, 특수한 참조 방식인 Phantom/Soft/Weak Reference가 존재하는 것을 볼 수 있다. 우리는 이 참조 방식들을 사용해서 GC의 동작에 제한적이나마 관여할 수 있게 된다. 1. Garbage Collector가 참조를 처리하는 방법GC는 가비지를 찾아 처리하고 메모리를 회수하는 목..
p.s 이 글에서 R8과 R8 컴파일러는 같은 것을 지칭하며, D8과 R8은 친구지만 서로 다른 개념입니다.코틀린 코드는 코틀린 컴파일러를 통해 바이트코드로 컴파일되며, 이 바이트 코드를 R8 컴파일러가 최적화하고 D8 컴파일러가 DEX 파일로 변환한다.이후 앱 실행시에 AOT나 JIT 컴파일을 통해 네이티브 코드로 변환되어 실행되는 원리이다.Proguard나 R8은 개발자가 설정 파일 외에는 추가적으로 설정해야하는 것들이 적어서 Proguard나 R8의 차이점이나 변경점을 모르는 경우가 많다.실 개발 단계에서도 안드로이드 개발자들은 각 라이브러리나 Kotlin 프로젝트에 필요한 Proguard 설정을 제외하고는 구체적으로 알아볼 필요성을 느끼지 못한다. 많은 라이브러리들이 정상적인 동작을 위해, 난독화..
오늘 포스팅 주제는 Kotlin의 유용한 기능인 sealed와 enum이다.둘 다 컴파일 타임에 타입 집합이 결정되어 타입 안전하고 when문을 exhaustive하게 함으로써 경우에 따른 명확한 처리 구문을 작성할 수 있도록 도와준다.오늘은 이 두 개념들의 역할을 넘어, 컴파일되었을 때의 차이점과 그로 인해 고려할 수 있는 것들에 대해 얘기해보고자 한다.1. sealed class코틀린의 sealed class는 모듈/패키지 외부에서 해당 클래스를 상속할 수 없도록 상속 가능 범위를 제한해서 클래스 계층 구조를 타입 안전하게 제공한다. 주로 여러 상태를 한가지 타입으로 다룸으로써 when문에서 모든 케이스를 명시적으로 처리하기 위해 사용된다.sealed class의 모든 하위 클래스는 컴파일 타임에 검..
약 1년 이상의 기간동안 회사에서 진행했던, 또는 사이드 프로젝트 팀에서 진행한 프로젝트들에 로버트 마틴의 클린 아키텍처를 적용해서 개발을 하고 있다.사실 진행한 여러 프로젝트들 중 굳이 클린 아키텍처를 적용할 필요가 없는 것들도 있었지만, 클린 아키텍처의 장단점을 지속적으로 경험함으로써 클린 아키텍처라는 개념을 딱딱하게 가져가기보다는 핵심 개념을 개발 과정에서 체득하기 위함이였다. 그렇게, 클린 아키텍처는 파고 들어갈수록 어떤 구체화된 하나의 아키텍처가 아니라, 더 유연하고 확장성 있는 개발을 위한 추상적인 개념들의 집합체로써 받아들이게 되었다.내가 클린 아키텍처를 좋아하는 이유도 어떤 고정적 구조를 가지는 이상적인 아키텍처라서 그렇다기보다는, 주니어 개발자인 나에게는 구조적 이점을 가져감으로써 소프트..
1. Drawable안드로이드의 Drawable API는 화면에 그래픽을 그리기 위한 추상화된 계층을 제공한다.Drawable은 BitmapDrawable, VectorDrawable , NinePatchDrawable , ShapeDrawable 등의 다양한 구현체들이 존재한다.지난 포스팅에서 Bitmap Drawable의 densityDpi별 대응을 위해 밀도별 스케일 펙터를 적용한 Bitmap을 사용한다고 했는데, 왜 사진이나 복잡한 이미지는 Vector Drawable로 사용하지 않는 지 의문이 들었다. 2. VectorDrawable주로 애플리케이션에서 사용하는 로고, 아이콘에 사용되는 Drawable 구현체이다.앞선 포스팅에서는 밀도 별 버전을 만들어서 해상도 별로 대응을 한다고 했는데, Ve..
1. 안드로이드의 해상도 대응안드로이드 기기들은 다양한 화면 크기를 가지고 있다. 어떤 기기에서는 인치당 160 픽셀을 사용하지만, 다른 기기에서는 480픽셀을 사용할 수 있다. 따라서 이런 차이를 고려하지 않는다면 이미지가 깨지거나 잘못된 크기로 보여질 수 있다. 이 같은 상황에 대응하기 위해 안드로이드에서는 View 간의 거리나 크기를 정의할 때 픽셀을 사용하지 않도록 권장하고 있다. 기기마다 픽셀 밀도가 다르므로 고정된 픽셀 값을 사용하면 기기의 크기에 따라 유동적으로 적용되지 않기 때문이다.안드로이드에서는 픽셀 대신 dp를 사용한다. 이는 Density-Independent Pixel의 약자로, 밀도 독립형 픽셀이다.표준 단위인 dpi를 기반으로 하여 중밀도(mdpi, 160dpi)를 기준으로 논..
안드로이드 스튜디오를 레이디버그 피쳐 드롭으로 업데이트한 이후에 갑자기 이런 오류가 발생했다.관련해서 국내 개발자들의 정보는 아예 없었고, 같은 증상이 발생한 외국인들의 토론 글이 있었지만 유용한 해결책은 찾을 수 없었다.다행히도 매번 invalidate cache하면 일시적으로 발생하지 않아서 그걸 반복하며 사이드 프로젝트를 개발하고 있었다. 그러다 이제는 이 비효율적인 프로세스를 먼저 해결하고 개발을 이어나가고자 여러 설정을 확인해봤는데,(1) compileSdk 버전도 변경하지 않았고(2) 현재 사용중인 버전의 AGP와 JDK의 조합은 문제 없이 잘 사용해오던 조합이였고(3) invalidate cache, build clean 등모든 방법을 다 해봤지만 일시적일 뿐, 완벽하게 해결되지 않았다. ..
1.Throwable과 Exception, ErrorThrowable은 예외와 오류의 최상위 클래스이다.예외와 오류의 차이점은 복구 가능성으로, 예외에 대해서는 개발자가 적절한 처리를 통해 정상적인 실행을 유지할 수 있으나 오류는 그렇지 않다. 이 때문에 이 둘을 구분하여 개발자가 핸들링할 수 없는 오류에 대해서는 처리를 하지 않도록 설계되었다. 2. Kotlin에는 checked exception이 없다Java에서는 RuntimeException의 서브클래스가 아닌 Exception들을 checked exception이라 부르며, 이에 대한 처리를 컴파일러 수준에서 강제한다. 하지만 Kotlin은 Jvm 기반으로 설계되었음에도 checked exception을 지원하지 않는데, 그 이유가 뭘까?💡Ko..
1. Dalvik과 ART안드로이드에서 사용하는 Dalvik과 ART(Android runtime)은 바이트 코드를 네이티브 코드로 변환하는 런타임이다.Dalvik의 JIT 컴파일 방식은 앱 실행 시마다 바이트코드를 해석하기 때문에 메모리 사용량이 높고 실행 속도가 느리다는 단점이 있고, GC도 모바일 환경에 최적화되어 있지 않아 구글은 이를 개선하기 위해 ART를 도입하게 된다.ART의 AOT 컴파일 방식은 설치 시에 미리 네이티브 코드로 변환하고 디스크에 저장한 후 실행 시에 저장된 네이티브 코드를 메모리에 로드해 실행함으로써 실행 속도를 개선하고, GC 메커니즘 또한 모바일 환경에 적합하도록 개선되었다. 2. Dalvik GC의 문제점Android 5.0 이전까지 사용된 Dalvik의 GC 메커니즘..