-
Android DataStore 를 사용하여 파일에 간단한 정보 저장하기Java-Kotlin/Android 2026. 1. 14. 23:45반응형
회사에서 제작하는 POS 프로그램의 정보(회사, 매장, 기기 번호)를 저장해 주어야 해서 Android에서 지원하는 두 개의 라이브러리를 비교해 보았다.
- SharedPreferences
- 동기적으로 작동
- Atomic Read/Write 보장 안됨
- Key-Value 저장 지원
- 파싱 에러 발생 시 RuntimeException Throw
- 코드가 간단하여 러닝커브가 낮음
- DataStore(Jetpack)
- 비동기적으로 작동
- Atomic Read/Write 보장 됨
- Key-Value, ProtoBuf(타입을 정의 및 직렬화 가능) 저장 지원
- 오류시 IOException로 에러를 Throw
- 코드가 SharedPreferences보다 복잡하여 러닝커브가 상대적으로 높음
- Kotlin Coroutine, Flow을 사용하도록 설계됨
고민해 본 결과 DataStore를 사용하여 개발하기로 했다.
DataStore를 선택한 가장 큰 이유는 이렇다.
- 프로그램 동작중 여러 쓰레드에서 Read/Write가 발생할 수 있음
- Flow를 사용하여 에러 핸들링이 상대적으로 간편함(Flow에는 catch 블록이 있음)
구현할 기능: 간단한 읽기(Read) 쓰기(Write) 정도만 구현하기로 했다.
현재 프로젝트는 Kotlin Multiplatform에 Koin으로 di 하는 환경이기에 DataStore 인스턴스와 그것을 inject 받아서 생성되는 DataStoreRepository를 구현하여 읽기 쓰기 기능을 제작했다.
Gradle
# libs.versions.toml androidx-datastore-preferences-core = { group = "androidx.datastore", name = "datastore-preferences-core", version = "1.2.0" }Koin DI
# KoinModule.kt single { DataStoreProvider.getInstance().getDataStore() } single { DataStoreRepository(get()) }DataStoreProvider
actual class DataStoreProvider private actual constructor() { private val dataStoreDirectory: File = Paths.get("${System.getProperty("user.home")}/POSPersistentResource/").toFile() private val dataStore = createDataStoreWithDefaults( emptyList() ) { dataStoreDirectory.resolve(dataStoreFileName).absolutePath } actual fun getDataStore(): DataStore<Preferences> { return dataStore } actual companion object { @Volatile private var instance: DataStoreProvider? = null actual fun getInstance(): DataStoreProvider { return instance ?: synchronized(this) { instance ?: DataStoreProvider().also { instance = it } } } } }DataStoreRepository
//데이터 스토어는 파일 저장 상수 느낌으로 사용 //제너릭을 사용 할 경우 세이브에는 문제가 없지만 리드시 타입이 맞지 않을 경우 에러가 발생 할 수 있음 class DataStoreRepository(private val dataStore: DataStore<Preferences>) { companion object { val TIMESTAMP_KEY = longPreferencesKey(name = "saved_timestamp") val COMPANY_CODE = stringPreferencesKey(name = "COMPANY_CODE") val STORE_CODE = stringPreferencesKey(name = "STORE_CODE1") val POS_NO = stringPreferencesKey(name = "POS_NO") } suspend fun <T> saveValue(key: Preferences.Key<T>, value: T): Boolean = try { dataStore.edit { preferences -> preferences[key] = value } true } catch (e: Exception) { e.printStackTrace() false } fun <T> readValue(key: Preferences.Key<T>, default: T): Flow<T> = dataStore.data .catch { exception -> // 예외를 다시 던져서 호출 측에서 처리할 수 있도록 합니다. throw exception } .map { preferences -> preferences[key] ?: default // 키에 해당하는 값이 없으면 기본 값 반환 } suspend fun <T> readValueOnce(key: Preferences.Key<T>, default: T): T { return readValue(key, default).first() } }읽기/쓰기 예시
// File DataStore에 저장 dataStoreRepository.saveValue(DataStoreRepository.COMPANY_CODE, baseSetting.companyCode) dataStoreRepository.saveValue(DataStoreRepository.STORE_CODE, baseSetting.storeCode) dataStoreRepository.saveValue(DataStoreRepository.POS_NO, baseSetting.posNo) // File DataStore에서 읽기 val companyCode = dataStoreRepository.readValueOnce(DataStoreRepository.COMPANY_CODE, "") val storeCode = dataStoreRepository.readValueOnce(DataStoreRepository.STORE_CODE, "") val posNo = dataStoreRepository.readValueOnce(DataStoreRepository.POS_NO, "")'Java-Kotlin > Android' 카테고리의 다른 글
SCP-380CII 영수증 프린터 안드로이드 SDK 연동기 (0) 2025.12.31 Kotlin Multiplatform(KMP) 윈도우 환경에서 File Lock을 이용한 중복 실행 방지 (0) 2025.12.17 Android에서 USB Serial 장치 연결 시 USB 권한 문제 해결기 (0) 2025.12.03 - SharedPreferences