반응형
네트워크 요청만으로 데이터를 처리하면 속도 저하와 오프라인 이슈가 발생할 수 있습니다. 이런 문제를 해결하기 위해 로컬 캐싱을 도입하면 앱의 안정성과 사용자 경험이 크게 향상됩니다. 이번 글에서는 Room + Flow를 활용해 네트워크와 로컬 캐시를 결합하는 방법을 소개합니다.
1. 로컬 캐싱의 필요성
- 네트워크 불안정 시에도 데이터 유지
- 앱 시작 속도 개선
- 서버 트래픽 절감
2. Room 데이터베이스 설정
Room은 SQLite 기반의 ORM 라이브러리로, Flow와 결합하면 자동 데이터 갱신이 가능합니다.
@Entity
data class UserEntity(
@PrimaryKey val id: Int,
val name: String
)
@Dao
interface UserDao {
@Query("SELECT * FROM UserEntity")
fun getUsers(): Flow<List<UserEntity>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUsers(users: List<UserEntity>)
}
3. Repository에서 네트워크 + 캐시 통합
Repository에서 네트워크 → Room 저장 → Flow 구독 순으로 데이터 흐름을 설계합니다.
class UserRepository(
private val api: ApiService,
private val userDao: UserDao
) {
fun getUsers(): Flow<List<UserEntity>> = flow {
// 1. 먼저 로컬 캐시 emit
emitAll(userDao.getUsers())
// 2. 네트워크에서 최신 데이터 가져오기
val remoteUsers = api.getUsers()
userDao.insertUsers(remoteUsers.map { UserEntity(it.id, it.name) })
}
}
이렇게 하면 앱이 시작될 때 Room에 저장된 기존 데이터를 즉시 보여주고, 이후 네트워크에서 새 데이터를 가져와 자동으로 UI에 반영합니다.
4. Compose UI에서 Flow 구독
ViewModel을 통해 Flow를 UI에서 관찰합니다.
@Composable
fun UserScreen(viewModel: UserViewModel) {
val users by viewModel.users.collectAsState(initial = emptyList())
LazyColumn {
items(users) { user ->
Text(user.name)
}
}
}
class UserViewModel(private val repository: UserRepository) : ViewModel() {
val users = repository.getUsers()
}
5. 캐싱 전략 요약
- Room DB와 DAO 정의
- 네트워크 + Room을 Repository에서 결합
- UI는 Flow를 구독해 자동으로 최신 상태 표시
6. 결론
네트워크 + 로컬 캐싱 전략을 적용하면 오프라인에서도 데이터가 유지되고, 사용자에게 더 빠른 응답을 제공할 수 있습니다. 특히 Room과 Flow를 함께 사용하면 데이터 동기화를 쉽게 구현할 수 있습니다.
다음 글 예고: 다음 글에서는 Compose + Paging 3로 무한 스크롤 구현하기를 다뤄보겠습니다.
반응형
'개발일기' 카테고리의 다른 글
| 멀티 모듈 + Clean Architecture로 Compose 앱 설계하기 (4) | 2025.09.19 |
|---|---|
| Compose + Paging 3로 무한 스크롤 구현하기 (3) | 2025.09.18 |
| 안드로이드 에러 처리 및 UI 피드백 전략 (2) | 2025.09.10 |
| Jetpack Compose와 네트워크 계층 연결하기 (2) | 2025.09.09 |
| 안드로이드 앱 네트워크 최적화 (캐싱, 연결 관리, 성능 개선) (3) | 2025.09.05 |