Android 성능: 앱을 실제로 느리게 만드는 요소들 (및 실용적인 처리 방법)
발행: (2025년 12월 17일 오전 12:45 GMT+9)
4 min read
원문: Dev.to
Source: Dev.to
“Android Performance”에 대한 올바른 이해
많은 글이 다음과 같은 방식으로 성능에 대해 이야기합니다:
- 객체 할당을 피하기
- 사소한 코드 최적화
👉 하지만 실제 앱에서는 성능 문제의 80 %가 다음에서 비롯됩니다:
- 메인 스레드 블로킹
- 메모리 누수
- 시작이 너무 무거움
- UI 렌더링 비효율
측정하지 않으면 → 최적화는 추측에 불과합니다.
흔한 실수
- 메인 스레드에서 API 호출
ViewModel에서 무거운 JSON 파싱- 복잡한 레이아웃을 지속적으로 inflate
onCreate에서 광고/SDK 처리
올바른 방법 (Kotlin)
viewModelScope.launch(Dispatchers.IO) {
val data = repository.loadData()
withContext(Dispatchers.Main) {
_uiState.value = data
}
}
원칙
- 메인 스레드 = UI 렌더링
- 모든 IO / 연산 → 백그라운드
시작을 느리게 하는 요소
- SDK를 너무 일찍 초기화 (광고, 분석)
- 불필요한
ContentProvider사용 - 첫 화면에서 복잡한 레이아웃 inflate
최적화 전략
- 초기화를 지연
- SDK를 지연 로드
- SplashScreen API를 올바르게 사용
lifecycleScope.launch {
delay(300)
initAds()
}
👉 사용자는 앱이 더 빨리 열리는 것을 느끼지만, 로직은 여전히 뒤에서 로드됩니다.
흔히 발생하는 메모리 누수
Context가 싱글톤에 보관됨- 콜백을
unregister하지 않음 - 어댑터 내
Fragment참조
모범 사례
- Activity
context를 보관하지 않음 - 필요할 때
WeakReference사용 onDestroyView에서 참조 정리
override fun onDestroyView() {
super.onDestroyView()
binding = null
}
📌 LeakCanary는 내부 프로덕션 빌드에서 반드시 사용해야 하는 도구입니다.
레이아웃 (XML)
문제
- 레이아웃 중첩이 너무 깊음
해결책
ConstraintLayout- 계층 구조 평탄화
DiffUtil+ 표준ViewHolder
Compose
문제
- 과도한 Recomposition
해결책
- State hoisting
rememberSaveable- Composable 내부에서 객체 생성 피하기
광고는 흔한 지연 원인
문제
- 메인 스레드에서 광고 로드
- UI가 안정되지 않은 상태에서 광고 표시
광고 모범 사례
- 광고 사전 로드
Application.onCreate에서 광고 초기화 금지- UI가 유휴 상태일 때만 광고 표시
if (ad.isLoaded && lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
ad.show(activity)
}
권장 도구
- Android Profiler
- Layout Inspector
- Systrace / Perfetto
- Firebase Performance
📌 데이터가 좋지 않을 때만 최적화하세요:
- 메인 스레드가 블록되지 않음
- 시작 시간 < 2 초
- 메모리 누수 없음
- UI 스크롤 부드러움
- 광고가 jank를 일으키지 않음
성능은 “더 똑똑한” 코드를 작성하는 것이 아니라, 실제 데이터를 기반으로 측정하고 분석하며 최적화하는 것입니다.