프로그래밍/Android 131

Coil 인터셉터를 활용한 이미지 로딩 최적화 방법

Coil의 이미지 파이프라인은 아래 5가지의 메인 파트로 이루어져 있는데, Interceptor는 그 중 첫번째로 실행되는 녀석이다. Interceptor -> Mapper > Keyer -> Fetcher -> Decoder 커스텀 Interceptor를 이용하면 일종의 캐시 레이어(Cache Layer)를 만들 수 있다. 요청을 가로채서 요청 파라미터를 수정하거나...HTTP Request를 했지만 휴대폰 내에 파일이 있다면 File로 돌려버리거나 말이다. 또, 앱에서 정의한 커스텀 스키마로 이미지를 불러오는 것도 가능해진다. 어찌되었건 지금 간단히 예시로 볼 것은 Unsplash 이미지를 불러올때 이미지 사이즈를 최적화 시켜주는 Interceptor다. (Github에 많이 떠돌아다니는 코드다 ㅋㅋ..

[Hilt] Custom Component의 활용 - 지역별 DB 생성하기

Hilt의 Component와 Scope Hilt에서는 안드로이드 앱의 다양한 생명주기에 맞는 미리 정의된 컴포넌트 들을 제공한다. 컴포넌트 위의 어노테이션은 해당 컴포넌트의 수명에 대한 바인딩 범위를 지정한다. 이렇게 어노테이션을 붙이면 해당 컴포넌트와 오브젝트는 생명주기를 같이하게 된다. 바인딩은 Scoped와 Unscoped 두 가지 유형으로 나누어지는데, 기본적으로는 Unscoped 바인딩이다. Unscoped: 해당 바인딩이 요청될 때마다 새로운 인스턴스가 생성됨 Scoped: 범위가 지정된 컴포넌트의 인스턴스 당 한 번만 생성되며, 해당 바인딩에 대한 모든 요청은 동일한 인스턴스를 공유함 @Module @InstallIn(FragmentComponent::class) object FooModu..

[Jetpack Compose] @Immutable과 @Stable이란

Stable과 Unstable Recomposition이 일어날때, Compose는 Stable과 Unstable로 유형을 구분한다. - Stable: 불변하는 것(Immutable), 혹은 Recomposition간에 값이 변경되었는지 여부를 추적할 수 있는 경우. - Unstable: Recomposition간에 값이 변경되었는지 알 수 없는 경우. 만약에 어떤 타입이 Stable하다면 Skip할 수 있지만 Unstable하다면 다시 그려야하므로, Stable과 Unstable하다는 것은 Compose에게 아주 중요하고 이것은 결국 성능에까지도 영향을 미치게 된다. 따라서 가능한한 클래스를 Immtable하게 만든다면 성능에 조금이나마 도움이 될 것이다. @Immutable @Immutable은 컴포..

Mainframer - 리모트 서버에서 빌드를 돌려보자

안드로이드 프로젝트 빌드 시간으로 고민하는 사람들이 많을 거라고 생각한다. 좋은 장비가 도움을 줄수는 있지만, 남아도는 좋은 서버가 있다면? (꽤 희망적인 가정인데) Mainframer나 Mirakle을 이용하면 SSH를 통해 리모트 머신에서 프로젝트를 빌드하고 결과를 로컬에 동기화 할 수 있다. 이것이 가능한데에는 rsync가 큰 역할을 한다. 우선 빌드서버와 SSH 연결이 가능한 상태를 가정하도록 하겠다. SSH 연결만 된다면 리모트 머신에서 딱히 준비할 건 없기때문이다. Mainframer Releases 페이지에서 최신 버전의 mainframer.sh를 다운받는다. . └── MyAndroidProject/ ├── app ├── .mainframer/ │ ├── config │ ├── ignore..

[안드로이드] plugin 적용 중 오류 해결방법: The request for this plugin could not be satisfied because the plugin is already on the classpath with an unknown version

오류발생 The request for this plugin could not be satisfied because the plugin is already on the classpath with an unknown version version catalog를 이용한 plugin 적용중에 "The request for this plugin could not be satisfied because the plugin is already on the classpath with an unknown version"라는 오류가 떴다. 당시 나의 plugins 블록은 다음과 같다. kapt를 추가하면서 문제가 발생했다. plugins { alias(libs.plugins.kotlin.android) alias(libs...

[안드로이드] Dialog Queue 구현하기

요구사항 앱 내 액션에 필요한 다이얼로그가 떠야해요. 하지만 유저가 클릭하지 않아도 서버가 푸시하면 앱의 어디서든, 언제든지 다이얼로그가 뜰 수 있어요. 튜토리얼을 할때는 튜토리얼용 다이얼로그를 제외한 모든 다이얼로그가 뜨지 않아야해요. 그리고 이 모든 다이얼로그들이 서로 꼬이지 않아야 해요. 다이얼로그를 한 두개 띄울때는 아무런 문제가 없었다. 하지만 요구사항에 따라 다이얼로그 추가되고, 이내 범벅이 되면서 다이얼로그 위에 다이얼로그가 떠버리거나 순서가 꼬여버려 좋지 않은 UX를 제공하게되는 결과를 야기했다. 아이디어 이것은 고등학교 급식 문제와 같다. 12시 종이 땡 치면 전교생이 우르르 급식을 먹으러오는 상황이다. 하지만 배식 라인(View)은 단 하나뿐! 3학년은 점심시간 중 자습시간이 있어 빨리..

[안드로이드] 순서보장 무한 페이저(Endless Pager) 만들기 with Jetpack Compose

무한 페이저를 만들때 아주 단순하게 생각하면 이렇게 만들기 쉽다. 하지만 이 경우, 초기 페이지가 내가 원하는 페이지가 되지 않는다. 실제 배열의 0번째부터 시작해야하는데, 실제 배열의 길이가 바뀌면 초기 페이지도 어떻게 될지 보장 할 수 없게 된다. val pageCount = Int.MAX_VALUE val pagerState = rememberPagerState( initialPage = Int.MAX_VALUE / 2 ) 무한 페이저는 한 두번이 아니라 나도 초기 페이지 계산하는 공식을 때려 맞추고는 했는데 빡대가리라 뭔가 수학적으로 설명을 하는게 안되서… 헤메고 있던 차, Jetpack Compose Endless Pager만들기 YouTube 강의 영상에서 아주 좋은 댓글을 발견했다. 이 방법..

[안드로이드] 부채꼴 카드처럼 돌아가는 Pager 만들기 (with Jetpack Compose Horizontal Pager)

오랜만의 Android 포스팅이다...ㅋㅋㅋ 도전적인 UI를 받아볼때 머리아프면서도 신나는 그런게 있다. 이번에 만들어본 건 손에 쥔 카드처럼 돌아가는 Pager다. (뭐라고 해야할까..? 용어를 아시는분은 댓글!) Jetpack Compose를 사용한지 3개월 남짓이라 숙련도가 다소 낮았기 때문에 간단한 이해부터 하고 작업에 들어갔다. “Jetpack Compose Pager Animation” 키워드로 검색해서 나오는 글들 중에 개인적으로 가장 깔끔했던 이 글의 설명을 빌려 Page Offset을 계산하는 방식을 후술해보려 한다. Page Offset 계산하기 Pager State 에는 currentPageOffsetFraction이라는 멤버변수가 제공된다. 이름에서 알 수 있듯이, 현재 페이지에 대..

Google I/O Extended Seoul 2023: Dagger Hilt로 의존성 주입하기

https://speakerdeck.com/fornewid/dagger-hiltro-yijonseong-juibhagi @네이버 웹툰 안성용님 발표자료를 글로 옮긴 것입니다. 의존성 주입이란? 의존성 주입은 하나의 객체가 다른 객체의 의존성을 제공하는 기법. 의존성 주입의 의도는 객체의 생성과 사용의 관심을 분리하는 것. // 의존성 주입 X class Car { private val engine: Engine = Engine() fun start() { engine.start() } } // 의존성 주입 예시 - 생성자에서 전달 class Car(private val engine: Engine) { fun start() { engine.start() } } // 의존성 주입 예시 - 필드 주입 clas..

[안드로이드] 회전목마(Carousel) 애니메이션 구현하기

게임에서 아이템이나 캐릭터 선택을 할때 회전 목마처럼 돌아가는 선택 애니메이션을 자주 볼 수 있는데, 이것을 안드로이드에서 구현해 볼 수 있는 기회가 생겼다. 사실 노가다를 하면 어떻게든 구현할 수 있지만, 이번에는 문제를 분석하고 쪼개보는 연습을 겸해봤다. 💡 요구사항: 3가지 종류의 상자가 있고, 이 상자들을 돌려가면서 열 상자를 선택하게 해주세요. 1. 상자 유형 데이터화 첫번째로 해야할 일은 상자를 데이터화하는거다. enum 클래스로 상자의 이미지, 가격, 이름이 담긴 LuckyBoxType을 만들어 주었다. enum을 사용한 이유는 순차적 접근이 sealed class보다 훨씬 쉽기 때문이다. enum class LuckyBoxType( val image: Int = 0, val cost: In..