최근 사이드 프로젝트를 진행하면서 서버와의 네트워크 통신을 위해 기기에서 토큰을 관리해야했다.
기존에는 SharedPreferences
로 구현했지만 최근 안드로이드 공식 문서에서 SharedPreferences
대신 Preferences DataStore
를 사용하라고 권장하고 있길래 적용해보기로 했다.
(DataStore
에는 Preferences DataStore
와 Proto DataStore
2가지 유형이 존재하는데 이 포스트에서는 Preferences DataStore
만 다룬다.)
Preferences DataStore
도 기본적으로는 SharedPreferences
처럼 Key-value 쌍으로 데이터를 저장한다는 점은 같다. 하지만 차이점은 크게 2가지가 있다.
기존의 SharedPreferences
는 데이터를 저장할 때 비동기 처리가 지원되지 않았기 때문에 ANR 문제에서 자유로울 수 없었다.
또한 SharedPreferences
는 데이터를 파싱하는 과정에서 런타임 예외가 발생할 가능성도 있었다.
이러한 SharedPreferences
의 단점을 보완한 게 바로 DataStore
이다.
implementation "androidx.datastore:datastore-preferences:{newer_version}"
먼저 build.gradle
파일에 DataStore-Preferences
라이브러리를 추가해준다.
<Preferences>
객체 생성private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "token")
preferencesDataStore()
메소드로 DataStore<Preferences>
객체를 생성해준다. Kotlin 파일 최상위에서 위와 같은 방식으로 DataStore<Preferences>
객체를 생성하면 싱글톤으로 활용할 수 있다.
<Preferences>
에 데이터 저장하기기본적으로 DataStore
는 비동기 방식, 그것도 Flow
로 데이터를 읽고 저장한다.
edit()
함수는 데이터를 트랜잭션 방식으로 업데이트할 수 있게 해준다. edit()
함수로 생성된 코드 블럭 내부는 모두 단일 트랜잭션으로 취급된다.
suspend fun updateAccessToken(accessToken: String) {
context.dataStore.edit { token ->
token[PreferencesKeys.ACCESS_TOKEN_KEY] = accessToken
}
}
<Preferences>
의 데이터 읽기DataStore<Preferences>
의 데이터를 읽을 때는 DataStore.data
속성을 사용한다.
DataStore.data
를 사용하면 Flow
데이터 스트림이 생성되어 원하는 데이터를 가져올 수 있다.
suspend fun getAccessToken(): Flow<String> = context.dataStore.data.map { token ->
token[PreferencesKeys.ACCESS_TOKEN_KEY].orEmpty()
}
레퍼런스