- 페이징 라이브러리를 사용한 것은 아니고, 파라미터로 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..
All
((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..
- 구글 클라우드나 파이어베이스에서 프로젝트 등록 시에 SHA-1 인증키 등록을 요구하는 경우가 있다. - SHA-1(Secure Hash Algorithm 1) 인증키는 앱 서명 인증을 위한 해시값. Google API(예: Google Maps, Firebase, Google Play 서비스 등)를 사용할 때, 특정 패키지 이름과 함께 앱의 신뢰성을 확인하는 역할을 한다. - 혹시 API 키가 외부에서 유출되더라도 등록된 SHA-1 키가 맞아야만 API 호출이 가능하므로 보안 강화 효과가 있다. - Android Studio에서 터미널을 열고, 다음과 같이 입력하면 잠시 후 확인이 가능하다../gradlew signingReport

안드로이드 스튜디오를 업데이트하고 빌드하는데, 갑자기 위와 같은 오류가 발생했다.명확한 원인을 알기 힘들어서 여러 가지 삽질을 했다... 일단 Settings - Gradle에서 현재 사용 중인 자바 버전을 맞춰줬다. 그리고 ilbs.versions.toml 파일에서 코틀린 버전도 업데이트했다.[versions]accompanistSystemuicontroller = "0.36.0"activityComposeVersion = "1.8.0-alpha07"agp = "8.5.0"biometric = "1.2.0-alpha05"converterGson = "2.9.0"glanceAppwidget = "1.1.1"hiltAndroid = "2.44"kotlin = "1.9.23"coreKtx = "1.12.0"..

- 운영 중인 서비스 로직은 서버로부터 새로운 리소스를 받으면 항상 고정된 경로의 로컬 파일 Storage 경로로 저장을 하고, Glide로 해당 이미지 리소스를 렌더링 하고 있었다. - 그런데 어느날 서버로부터 변경된 리소스를 내려받아도 렌더링 단계에서 해당 리소스가 갱신되지 않는 문제를 발견. - 분명히 로컬 저장 단계까지 변경된 리소스가 저장되는 것까지 확인했으나 원인은 Glide 동작 설정에 있었다. - Glide는 기본적으로 캐싱 기능을 가진다. 디스크 캐시와 메모리 캐시를 활용하여 이미지를 빠르게 로드하고 불필요한 네트워크 요청을 줄이는 기능을 가지고 있다.1. 메모리 캐시 (Memory Cache)이미 로드된 이미지를 RAM에 저장하여 빠르게 다시 불러올 수 있도록 함앱이 종료되거나 메모리가..

- 이런 구조의 TimePicker를 가진 Sheet가 존재하는데, TimePicker의 각 hour, minute 부분은 별도의 EditText로서 사용자의 포커스 온이 가능합니다. - 그런데, 키보드에서 '다음' 또는 '확인' 버튼을 누르지 않는 이상 전체 TimePicker에 해당 값이 전달되지 않으면 UI 및 데이터 업데이트에 문제가 있었습니다. - 사실 아래 설정을 통해 아예 사용자 입력을 비활성화시키고 스크롤만 가능하게 할 수도 있습니다. android:descendantFocusability="blocksDescendants" - 하지만 최대한 사용자의 입력을 존중(?)하기 위해 사용자가 Sheet를 닫을 시, 각 EditText의 포커스 상태를 검사하고 값을 가져오는 처리를 진행했습니다. ..

Application 클래스란?Application 클래스는 Android 애플리케이션의 전반적인 상태를 관리하는 기본 클래스입니다.앱이 실행될 때 가장 먼저 생성되며, 앱이 종료될 때까지 유지됩니다. - 싱글톤처럼 동작하며, 어디서든 접근 가능 - 앱의 생명 주기 관리- 앱 전역에서 공유해야 하는 데이터(예: SharedPreferences, DI Container, Theme, Locale 등)를 관리- 의존성 주입(Dagger/Hilt), Firebase 초기화, Crashlytics 설정 등 각종 초기설정을 여기서 진행 - 반드시 Manifest에 선언해주어야 한다.
memoText.text = Html.fromHtml(timeBlock.description?.replace("\n", ""))- 위와 같은 코드가 존재한다. Html.fromHtml()을 사용하여 HTML 태그를 포함한 문자열을 Spanned 형태로 변환하여 TextView에서 HTML 렌더링을 할 수 있게 하는 코드이다. - replace("\n", "")를 통해 개행(\n)을 태그로 변환하여 HTML에서 줄 바꿈을 유지하도록 한다. - 그런데, 사용자가 만일 EditText에 이런식으로 입력해 버리면 통째로 사라져 버린다. 그래서 입력된 문자를 HTML 엔티티로 변환하는 과정이 필요하다. fun fromHtmlSafe(source: String?): Spanned { val safeTex..