1. EditText TextWatcher로 검색처리 과부하 리펙토링
안드로이드 EditText에서는 TextWatcher를 이용하여 내부의 값 변경이 될 경우 listener를 추가하여 알맞은 동작을 구현할 수 있습니다. 대부분이 상황에는 검색이나 text의 원화표시 같은 동작을 추가합니다.
기존의 NoteApp 같은 경우에도 리사이클러뷰의 적용된 어댑터에서 searchNotes라는 함수를 호출하여 검색 처리를 하고 있습니다.
이 코드 자바로 구현되어 있으며 해당 작업은 Timer를 이용하여 비동기처리를 하고 있습니다. 이 코드는 여러 이슈가 생길 수 있습니다. textWatcher에서 바로 해당 작업을 실행하기에 기존의 Timer는 참조되지 않지만 여전히 실행될 것입니다. 그렇지만 타이머를 취소하지 않습니다. 그러면 반복문은 계속 실행되면 심하면 기기에 무리가 갈 수 있습니다. 그래서 Java에서 Kotlin으로 리팩토링할때 이 부분을 참고하여 개발하였습니다.
이런 식으로 Timer 대신 코루틴을 사용하고 검색 전에 기존의 코루틴을 취소하도록 수정하였습니다. Adapter 같은 경우에도 ListAdapter를 이용하여 따로 리스트를 만지지 않아도 되며 viewModel에서 StateFlow를 구독하여 변경 때마다 적용할 수 있도록 하였습니다.
2. ViewModel 사용
기존의 코드 중 가장 달라진 점이 뭐냐라고 말한다면 ViewModel이라고 말할 수 있습니다. 기존 코드에서는 모든 액티비티의 Data의 관리를 다른 곳에 넘겨주지 않는 MVC의 구조가 심했습니다.
이런 방법은 Configuration Change 같은 이벤트에서 큰 위험을 유발할 수 있습니다. 그 밖에도 해당 데이터의 관리 시 모든 데이터가 바뀌는 곳마다 똑같은 로직을 작성해줘야 합니다. 이를 함수로 만들어 중복을 최소화할 수도 있겠지만 ViewModel에서 LiveData나 Flow를 경험한 저에게는 그렇게 좋은 선택은 아니었습니다.
그렇기에 이런 식으로 Flow를 사용하여 data를 관리하기 쉽게 만들었습니다. 여기에 CleanArchitecture도 추가가 되니까 코드를 분리하여 관리하기 쉬워졌습니다.
3. View 이미지 사본저장
기존에 이미지를 이용해 노트를 만들고 사용자에게 보여주기 위해서 해당파일의 절대경로가 담기 file uri를 db에 저장하고 해당 uri를 저장하는 방식입니다. 이는 이미지를 앱에서 관리하는 것이 아니라 다른 곳에서도 관리를 할 수 있기에 이미지 손상이나 삭제가 될 경우 앱에서는 해당이미지 불러오지 못할 수도 있습니다. 그렇기 대체할 수 있는 방법을 찾았습니다.
그중 하나가 이미지의 사본을 앱 내부 저장소에 저장을 하는 것입니다. 이렇게 되면 보안적으로나 관리하기도 쉬워집니다.
이때 이미지의 경우 bitmap을 png로 저장하는 방식을 선택하였습니다. 그리고 앱에서만 보이는 이미지이기 때문에 그렇게 큰 용량의 이미지는 필요 없습니다. 그래서 앱에서는 이미지를 선택해서 가져온 uri를 bitmap으로 변형하고 view에서 보이는 이미지의 크기를 비교하여 작은 이미지를 저장하는 방식을 선택하였습니다. 또한 imageChanged라는 값으로 이미지를 바꾼 적이 있는지를 확인하여 무차별적인 저장을 막았습니다.
4. 사용하지 않는 파일의 삭제
이미지의 무차별 저장을 막는다고 해도 노트의 이미지가 변경된 노트가 삭제된다면 기존의 사본은 여전히 앱의 내부 저장소에 남게 됩니다. 매번 삭제가 되거나 변경이 있고 나서 이러한 부분을 없에도 되지만 매번 이렇게 할 필요는 없습니다. 이런 부분을 감지하고 수정하는 것이 매 동작마다 필요한 것은 아닙니다. 앱에서 동작시 1번? 정도면 충분이 정리를 할 수 있습니다. 그렇기에 앱시작시 사용되지 않는 이미지의 삭제를 할 수 있도록 구현하였습니다.
5. 이미지 가져오기 이슈
API 30 이후부터 에뮬레이터에서 이미지를 가져오려고 하면 이미지가 선택이 되지않는이슈가 생겼습니다. 권한 같은 경우에도 33 이후부터 권한이 READ_EXTERNAL_STORAGE에서 READ_MEDIA_IMAGES로 바뀐 것이기에 30 버전이 이상이 있으면 안됐습니다. 이이슈는 이상한 게 34 버전의 에뮬레이터 와 실제 기기에서 테스트했을 때 다른 결과가 나타났습니다. 에뮬레이터 같은 경우 다른 버전과 비슷하게 이미지를 가져오는 창이 나오지 않았지만 실제 기기에서는 이미지를 가지고 올 수 있었습니다. 이때 디버깅을 해보니 조건문을 통과를 하지 못하여서 그런 결과가 나왔던 것입니다.
intent.resolveActivity는 해당 인텐트를 실행할 수 있는지 검사하는 메서드입니다.
https://developer.android.com/training/package-visibility?hl=ko
위 링크에서 보다시피 Android 11(API 수준 30) 이상을 타기팅하고 기기에 설치된 다른 앱에 관한 정보를 쿼리 하는 경우 시스템은 기본적으로 이 정보를 필터링합니다.라고 나옵니다 필터링 동작은 앱이 기기에 설치된 모든 앱을 감지할 수는 없어 null이 나오게 되는 거죠. 그래서 try catch문으로 Intent를 실행하여 이슈를 해결하였습니다.
'안드로이드 > 안드로이드' 카테고리의 다른 글
안드로이드에서 UI를 업데이트 하는 방법 (0) | 2024.11.07 |
---|---|
안드로이드 MVVM 카카오 로그인 이슈 (0) | 2024.11.01 |
CNA(Chirag Note App) 클론코딩 & 리펙토링 회고 (1) | 2024.10.01 |
CIP(Cat-Image-Provider) 프로젝트하면서 생긴 이슈 및 해결 ,기술 정리 (1) | 2024.09.27 |
CIP(Cat Image Provider) 개발 회고 (0) | 2024.09.26 |