object TimeConverter { /** * KMP 용 date & time 변환을 위한 라이브러리, kotlinx-datetime * * 오픈 API: openweathermap.org * * ``` * "timezone":"America/Chicago", * "timezone_offset":-18000, * "current":{ * "dt":1684929490 * . . . * } * ``` * * 1. UTC 타임 포맷을 사용하는 경우, 1000으로 나누는 이유 * 2. TimeZone이란? * 2-1. TimeZone 변환 중 예외 발생 시 사용하는 FixedOffs..
한달전부터 Manifest-for-android-interview라는 책으로 북 스터디를 진행하고 있다.면접 질문 모음집? 같은 느낌의 책이고, 안드로이드 전반에 걸친 질문들이 수록되어 있는 책이다.android GDE이신 sky-doves 님이 집필하신 책인데, 난이도(깊이)는 중-중상 정도 되는 것 같다. 스터디를 진행하면서 아쉬웠던 점은 책에 적혀있는 지식들로만 스터디가 진행된다는 점이였다.중소기업 면접이라면 단순히 A가 무엇인가요?라고 묻고 끝나는 경우가 많겠지만,근거 있는 기술 사용을 중요하게 여기는 대기업들의 면접을 가게 될 경우에는 작은 주제라도 꼬리 질문이 깊이 들어올 수 있기 때문에 피상적인 학습은 오히려 면접 상황에서 독이 될 수 있다. 그래서 매 스터디 회차마다 공용 리포지토리에 고민..
안드로이드 UI 대세인 컴포즈를 사용할 때에는 좀 더 스테이블한 Coil 라이브러리를 사용한다.하지만 xml을 통해 뷰 시스템을 사용하는 경우에는 캐시 성능이 뛰어난 Glide를 사용하는데, 오늘은 Glide의 디스크/메모리 캐시가 내부적으로 어떻게 구현되어 있는지에 대해 살펴보고자 한다. 우선, Glide의 캐시는 크게 메모리 캐시와 디스크 캐시로 구성되어 있다.우리는 diskCacheStrategy() 메서드를 통해 디스크 캐시 전략을, isMemoryCacheable/skipMemoryCache 메서드 등을 통해 메모리 캐시 사용 여부를 설정할 수 있다. 0. 전체 이미지 로딩 과정ActiveResources 조회MemoryCache 조회DishCache 조회네트워크/파일 로딩Glide를 통해 이미..
Flowflow는 우리가 비동기적으로 처리해야할 값의 스트림을 나타낸다. Flow 인터페이스를 통해 요소들을 모으고, Flow의 끝에 도달할 때까지 각 값을 처리한다.public interface Flow { public suspend fun collect(collector: FlowCollector)} 위 코드는 Flow 인터페이스로, 유일하게 collect를 멤버 함수로 가지고 있다. ❓ 왜 collect만 멤버 함수로 가지고, 다른 함수들은 확장 함수로 정의하도록 설계한걸까?Flow 인터페이스는 Cold 스트림을 수집한다는 한 가지의 책임만 가지도록 설계되었다.모든 연산자들을 멤버로 정의하면 API가 불필요하게 커지고, 구현체마다 모두 구현하거나 상속해야 하기 때문이다.그래서 확장 함수라는 기..
이펙티브 코틀린은 자주 찾아 꺼내보는 책이라 기억은 안 나지만, 아마 3회독째인 것 같다.Java에서 Kotin으로 넘어오는 과정에서 빠르게 습득한 빈약한 지식을 기반으로, 코드를 관습적으로 작성하는 경향이 있었다고 생각해서 그걸 개선하기 위해서 꾸준히 읽고 있다.왜 어떤 주제는 포스팅하고, 어떤 주제는 포스팅하지 않나요? 라고 묻는다면, 내 코드를 실질적으로 개선할 수 있는 깨달음을 준 챕터들에 대해서만 작성하고 싶기 때문이다. 함수 타입 파라미터코틀린은 다중 패러다임 언어이다. 그 중에서 함수형 패러다임의 핵심 개념 중 하나가 "고차 함수"이다.고차 함수는 함수를 인자로 받거나 함수를 반환하는 함수를 말한다. 오늘 포스팅에서는 그 중 "함수를 인자로 받는" 경우에 대해 inline 한정자를 붙이면 어..
우리는 서버 Api를 호출할 때, Kotlin 객체를 Json 객체로 직렬화해서 전송하고 Json 객체를 Kotlin 객체로 역직렬화해서 사용하게 된다. 왜 이런 과정이 필요한 걸까?제대로 된 이유를 알지 못한 채 당연한 듯 생각했던 이 과정을 뜯어보자. 객체를 직렬화해서 전달하는 이유그런 일련의 과정이 필요한 이유는, 객체는 단순히 메모리 상에서 변수와 포인터로 이루어진 무언가이기 때문이다.JVM 메모리 상의 어떤 객체는 다른 곳에서 사용할 수 없기 때문에, 컴포넌트 간의 데이터를 공유하거나 서버 통신, DB 저장 등을 위해서는 직렬화한 후 수신부에서 변환하여 해당 환경에서 사용할 수 있는 데이터로 직렬화해야 한다. 직렬화 과정에서는 객체를 독립적인 데이터 포맷인 Json, Xml, 바이트 스트림 등으..
가변성을 활용하면 변동성이 큰 데이터에 대해 명시적이고 단순하게 처리를 할 수 있다.기존 객체를 복사하지 않고 직접 변경함으로써 불변 객체에 비해 메모리 할당이나 복사에 드는 오버헤드가 적다는 장점 또한 존재한다. 하지만 간혹 코드를 짜다보면, 가변성이 굴린 스노우볼로 인해 트러블슈팅에 애먹었던 경험들이 있을 것이다. 가변성의 이점을 취하기 위해 우리가 간과할 수 있는 문제점이 뭘까?가변성이 가지는 문제점코틀린의 구성요소들 중 일부는 상태를 가질 수 있도록 설계되어 있으며, 그 중 우리가 가장 자주 사용하게 되는 건 가변 프로퍼티나 MutableList, MutableSet, MutableMap 등이 있다.사용자는 이를 통해 가변성을 활용할 수 있는데, 여기서 문제는 이 가변성을 어떻게 활용하느냐에 따라..
1. Context안드로이드에서 Context는 어플리케이션 컴포넌트들과 안드로이드 시스템 사이의 인터페이스 역할을 한다.우리는 Context를 통해서 시스템과의 상호 작용부터 우리가 주로 사용하는 리소스, 어셋, 파일, 컴포넌트 시작, 시스템 서비스 접근, 권한 확인을 수행하게 된다. 2. Application context, Activity context✨ Application contextApplication 전체 생명주기 동안 유효한 context이다. Activity context처럼 UI와 관련된 속성을 포함하지는 않지만, 전역적으로 어플리케이션의 정보를 제공한다.AlarmManager, LocationManager를 사용할 때, Activity context를 사용하여 시스템 서비스와 연동할..
💡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는 가비지를 찾아 처리하고 메모리를 회수하는 목..