전체 글

AI가 답을 알고 있어도, 우리는 '왜'인지 알아야 합니다.
- 이전에 브로드 캐스트 리시버로 자정이 되면 위젯을 갱신하는 로직을 구현했었다. - 그런데 이때 예약을 위해 사용된 setExact()가 반드시 알람 권한을 획득해야만 하는 함수인데 사용자가 알람 권한을 허용하지 않고 앱을 사용하다 보면 위와 같은 Exception이 발생하는 것이다. - 사실 알람 설정 기능이 아니고, 이미 다른 영역에서 권한 처리를 받도록 구성되어 있으며, 해당 기능은 백그라운드에서도 동작해야하는 부분이라 알람 권한 없이도 기능이 동작하도록 구성했어야 한다. - 이를 위해 setAndAllowWhileIdle()을 사용했다. 권한 필요 없이 Doze에서도 울릴 수 있는 유일한 대안이다. - 하지만 setExact()와 다르게 정확한 시간을 보장하지는 않는다. 약 1~2분 정도 차이가..
- 의존성 주입이라는 개념이 있다. 객체가 필요한 의존 객체를 외부에서 주입받아 사용하는 설계를 말한다. - 보통 일반적으로 수동적 의존성 주입 처리가 진행된다. 하지만 지연 초기화, nullable 처리, 코드 중복량 증가에 대한 문제점들이 시간이 지날수록 드러난다. - 이런 문제점들을 줄이기 위해 DI를 컴파일 시점에서 처리해 런타임 성능을 최적화하고, 어노테이션으로 객체 간 의존 관계를 관리할 수 있는 라이브러리 Hilt가 있다.https://developer.android.com/training/dependency-injection/hilt-android?hl=ko Hilt를 사용한 종속 항목 삽입  |  App architecture  |  Android Developers이 페이지는 Cloud..
- 캘린더형 위젯을 지원 중인데, 자정이 지나도 위젯이 갱신되지 않고 전날 날짜가 그대로 유지되는 현상이 발견되었다. - 자정이 되는 시점을 감지하고, 위젯을 update 시켜주는 로직 구성 작업이 필요했다.  - 안드로이드 4대 컴포넌트 중 하나인 BroadcaseReceiver를 사용하면 된다.What are the four components of an android application?ActivitiesServicesBroadcast ReceiversContent Providers- 자정 시간을 알람 시간으로 등록하고 해당 시간이 되면 PendingIntent를 통해 리시버를 동작시킨다.class MidNightReceiver: BroadcastReceiver() { override fun..
- 보통 뷰에 특정 배경색 또는 테두리 효과를 주입하는 것은 아래처럼 drawable XML 소스를 구현하면 된다.  - 하지만 테두리의 경우 그러데이션을 자체적으로 지원하지는 않은 것으로 확인되어 Paint를 활용해 그려서 커스텀 뷰를 구현하는 작업을 진행했다.class GradientStrokeButton @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : AppCompatImageButton(context, attrs, defStyleAttr) { private var cornerRadius = 0f private var bord..
- 자사 서비스에서 Realm DB를 활용하고 있다. - Realm DB는 빠르고 가벼운 로컬 데이터 저장을 위한 객체 기반 데이터베이스이다.  - Realm DB의 객체로 리스트를 구성할 때는 RealmRecyclerViewAdapter를 이용하여 구성할 수 있다. - 내부 구성은 일반 RecyclerView와 크게 다르지 않다. 하지만 getItem 등의 함수가 RealmDB 자체에서 오리지널 인스턴스를 가져오는 방식으로 동작한다./** * Returns the item in the underlying data associated with the specified position. * * This method will return {@code null} if the Realm instance has ..
- 기존 프로젝트 내에 인앱 결제 관련 로직이 너무 노후화되어 있었고, 함수도 분산되어 있어서 관리하기가 난해했다. - 최근에 모듈을 최신화하면서 주요 함수를 BillingManager라는 싱글톤 object로 정리했는데, 그 내용을 기록해 본다.결제 모듈 초기화object BillingManager { private var billingClient: BillingClient? = null /** * 결제 모듈 초기화 완료 여부 */ fun isReady(): Boolean { val client = this.billingClient ?: return false return client.isReady }- 결제 모듈 초기화 완료 여부를 확인하는..
- 페이징 라이브러리를 사용한 것은 아니고, 파라미터로 page: Int를 보내고 response로 hasNext: Boolean을 수신받을 수 있는 형태의 api에서 페이징을 자체 코드로 간단하게 구현한 예시다.상단 구성 - Scaffold 구조로 상단에 TopAppBar를 가지고 내부 content로 리스트를 가지는 화면에서 페이징을 구성했다.Scaffold(topBar = { TopAppBar(modifier = Modifier.padding(start = 12.dp), title = { Text() }, navigationIcon = { IconButton(modifier = Modifier .size..
((Vibrator)AppCore.context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(10);- 기존 코드에서 사용하던 디바이스 진동 효과를 발생시키는 vibrate 코드가 deprecated 되어 있었다. - 10m/s 동안만 일시적으로 진동을 울리는 코드인데, Android O(26)부터 아래와 같이 수정이 필요하다.Vibrator vibrator = (Vibrator) AppCore.context.getSystemService(Context.VIBRATOR_SERVICE);if (vibrator != null && vibrator.hasVibrator()) { // 진동 기능이 있는지 확인 vibrator.vibrate(Vibrat..
Places Api (New) 활용- 사내 프로젝트에 예전부터 Places SDK가 적용되어 위치 검색 기능을 담당하고 있었는데, 어느 시점부터 아래와 같이 오류가 표시되는 지역들이 증가하기 시작했다.- Google Places API(신규)는 기존 Places API를 대체하는 서비스로, 장소 검색, 자동완성, 상세 정보 조회, 좌표 변환 등의 기능을 제공한다. 그리고 데이터가 등록된 장소 개수 자체도 훨씬 많은 것으로 알고 있다. - 기존에 사용하고 있던 API Key가 있다면 Places Api (New)를 사용으로 설정한 뒤, 제한 목록에 추가해 주면 된다.- 신규, 기존 상관없이 적어도 아래 목록은 키 제한 API 목록에 포함시켜야한다. 그렇지 않다면 권한 거부 오류가 발생한다.Places SD..
- apng라는 파일 형식이 있다. PNG 포맷을 기반으로 한 애니메이션 이미지 포맷으로서 GIF와 비슷하지만 더 높은 품질과 투명도를 지원하는 특징이 있다. - 기존에 png, jpg, gif를 활용했었으나 용량 관리 측면에서 apng가 유리하여 새롭게 사용하게 되었다. - APNG 파일은 PNG와 동일한 구조를 가지므로, APNG를 지원하지 않는 프로그램에서도 정적인 PNG 이미지로 보일 수 있음 (하위 호환성) - 그래서 apng가 움직이지 않고 정적인 이미지로 보인다면, 사실 완벽한 렌더링에는 실패했거나 해당 기반 프로그램이 지원하지 않는 것 - 토스와 라인도 apng를 많이 사용하고, 라인에서 안드로이드에서 해당 형식 렌더링을 위한 라이브러리도 구현해 주어서 직접 사용해 봤다. https://g..
SeungYong.Lee
Win-Dev