목록Android (57)
Hanbit the Developer
구현 결과 1. Touch to move 터치하여 움직이기를 구현하기 위해 저는 setOnTouchListener()를 다음과 같이 적용하였습니다. // 이동 var startTouchX = 0.0f var startTouchY = 0.0f var startPoseImageX = 0.0f var startPoseImageY = 0.0f binding.root.setOnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { startTouchX = event.x startTouchY = event.y startPoseImageX = binding.imagePose.x startPoseImageY = binding.imag..
배경 val outputStream: OutputStream = FileOutputStream(imageFile) bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream) outputStream.flush() outputStream.close() 위와 같은 코드로 /Pictures/AppName 같은 루트에 이미지를 저장을 하고 갤러리 앱에 들어가보면, 저장된 사진이 그 즉시 보여지지 않습니다. 갤러리 앱에 보여지는 데 1~3분 정도가 소요되곤 하여 앱을 사용하기에 매우 불편하였습니다. 해결 과정 원인 및 해결책을 찾을 수 있었던 과정은 다음과 같습니다. 1. SNOW 앱은 즉시 사진이 갤러리에 보여지기 때문에, 혹시나 저장되는 위치가 잘못된 것인지 ..
서론가장 인기있는 MVVM 및 Clean Architecture를 Retrofit2, Hilt, Recycler View와 함께 쓴 매우 간단한 repository를 작성하였고, 이에 대한 설명이 이 글의 주요 내용입니다. 위 내용들을 실제 예시 코드를 통한 빠르게 학습하고자 하시는 분들이 타겟입니다. 이 프로젝트의 앱은 OpenAPI(https://reqres.in/) 서버와 통신하여 유저 리스트를 READ하고 이를 RecyclerView에 표현하는 내용의 앱입니다. https://github.com/hanbikan/recycler-view-with-mvvm-hilt-retrofit2 GitHub - hanbikan/recycler-view-with-mvvm-hilt-retrofit2: An examp..
서론 해당 프로젝트를 하면서 객체지향, 클린 아키텍처, MVVM과 관련된 고민이 많았습니다. 그 과정에서 코드를 뒤엎는 리팩토링이 정말 많았는데, 그 과정을 기록한 내용입니다. (해당 글의 내용은 좋은 코드를 위한 과정일 뿐 정답이 아니란 점..!) [PICK-70] 클린 아키텍처 적용 기존에 네이밍(item, model)도 혼재되어 있었고 레이어 또한 제대로 구분되지 않은 채로 방치되어 있었습니다. 게다가 translator에서 책임을 져야할 내용(entity 혹은 dto를 model로 변환시키는 로직)을 repository가 처리하고 있었습니다. 이러한 많은 문제점을 아래 사진과 같은 클린 아키텍처를 적용함으로써 해결하였습니다. 기존의 더러운 코드로 인해 불편함을 겪다가 적용을 하니 각 영역이 왜 필..
배경Splash Screen에서 특정 작업을 마친 후에 앱으로 진입하게 되는데, 이 시간이 너무 긴 것처럼 느껴져서 개선을 진행하게 되었습니다.분석먼저 SplashActivity의 코드를 분석해보았고, 다음과 같은 사실을 알 수 있었습니다.API 호출과 Kakao Login 작업에서 가장 큰 시간 소요가 있었습니다.두 작업이 순차적으로 진행되고 있었습니다.따라서 두 작업을 병렬로 처리하는 것이 포인트입니다.병렬 처리사실 여러 개의 suspend function(Non-blocking)을 병렬로 처리하는 것은 awaitAll() 함수만 사용하면 꽤 쉽게 처리할 수 있습니다. 하지만 저의 경우에는 Kakao Login을 사용하고 있었고, 카카오에서 콜백 함수로 비동기 처리를 제공하고 있었습니다.(Asynch..
배경 모바일 어플리케이션의 매우 치명적인 단점 중 하나는 바로 업데이트입니다. 사용자 입장에서 앱을 업데이트하는 것은 매우 귀찮은 일이어서 잘 하려고 하지 않습니다. 따라서 어떻게 하면 업데이트를 최대한 줄이고 앱을 개선해나갈 것인지에 대해 고민해야 합니다. Rich Text를 사용하면 앱을 업데이트되지 않더라도 TextView의 내용은 물론이고 스타일, 색상, 크기를 변경할 수 있으며 심지어 이미지까지 첨부할 수 있습니다. 단 1개의 TextView만으로 위와 같은 결과를 낼 수 있습니다. 이렇게 디테일한 내용을 앱 업데이트 없이도 적용할 수 있습니다. Server Driven UI를 구현함으로써 이를 적용할 수 있으며, 서버에서 텍스트의 디테일한 attribute를 보내준다는 가정 하에 구현이 가능합..
배경 앱 메인 화면에 진입을 할 때, 정보를 로드해서 뷰에 나타나기까지의 시간이 조금 있었고, 짧은 시간이긴 하지만 사용자 경험이 별로 안 좋아보였습니다. 이에 따라 저는 Room을 통해 이전의 데이터를 로컬에 캐싱하고, 이 데이터를 이용하여 네트워크 처리가 되기 이전에 캐싱된 데이터를 미리 보여주기로 하였습니다. 개요 Room 관련 세팅 Room Entity, Dao, Repository RoomDatabase, TypeConverters, DI ViewModel에 Offline Cache 적용 구현 1. Room 관련 세팅 build.gradle(root) buildscript { ext { roomVersion = '2.4.3' } } build.gradle(module) apply plugin: ..
서론 결과는 위와 같습니다. 구현 먼저 구현하려는 커스텀 뷰는 다음과 같은 특징이 있습니다. 1. 선택된 아이템의 indicator의 width와 color가 다르다. 2. 위 특성의 변화가 연속적으로 이루어진다. layout_custom_indicator.xml 뷰가 그려질 레이아웃입니다. layout_indicator.xml 각 indicator의 레이아웃입니다. indicator_background.xml 위 layout_indicator에서 참조하는 리소스 파일입니다. 여기서는 shape가 rectangle이지만, 이후에 radius를 줌으로써 둥그런 indicator를 그리게 됩니다. attrs.xml /res/values/attrs.xml 내부에 다음과 같은 코드를 작성하여 커스텀 뷰에 특성을..
문제 상황 해결 과정 1. 의심되는 코드들을 하나씩 주석처리 해가며, 어떤 코드를 지우면 문제가 발생하지 않는지 체크 범위를 좁히다보니, customView(as TextView)에 setTypeface() 함수에서 문제가 발생한다는 것을 발견하였다. 처음에는 indicator 관련 코드를 위주로 브레이크 포인트를 걸거나 주석 처리를 했었는데, 전혀 연관이 없어 보이는, 탭의 TextView와 연관이 있었다. textView.setTypeface( null, if (isSelected) Typeface.BOLD else Typeface.NORMAL ) 2. setTypeface() 함수, Typeface 코드 분석 native code의 벽에 가로막혔으며, 시간을 너무 지체하면 안 되므로 여러 시도를 해..
서론 먼저, 구현하게 될 내용은 다음과 같습니다. 위 영상을 보면, 아이템이 선택되면 파란색 배경이 다이다믹하게 움직입니다. 이번 글은 해당 Indicator를 중심으로 설명할 예정입니다 :) (com.google.android.material.bottomnavigation와 androidx.navigation를 기준으로 구현했습니다.) 구현 IndicatorBottomNavigationView.kt 사실 이 글의 내용의 전부입니다. 개요는 다음과 같습니다. - BottomNavigationView를 상속하는 IndicatorBottomNavigationView 클래스 생성 - startIndicatorAnimation() - indicator: RectF, paint: Paint를 이용한 애니메이션 ..