Android DataStore

HEETAE HEO·2022년 6월 28일
0
post-thumbnail

DataStore

DataStore는 SharedPreferences를 비동기로 사용하기 위한 라이브러리입니다. DataStore는 프로토콜 버터(구조화된 데이터를 직렬화 하는 메커니즘)를 사용하여 Key-value타입 혹은 유형이지정된 객체를 로컬에 저장할 수 있는 기능입니다.

DataStore는 Corouine + Flow를 사용할 수 있어 비동기적이고 일관적인 트랜잭션 방식으로 데이터를 저장합니다.

DataStore는 key-value 타입으로 구성되어 있는 Preferences DataStore랑 사용자가 정의한 데이터를 저장할 수 있는 Proto DataStore 이렇게 두 종류가 존재합니다. Proto DataStore를 사용하게 된다면 프로토콜 버퍼를 이용하여 스키마를 정의해야합니다. 이는 데이터 타입을 보장해줄 뿐더러 SharedPreferences 보다 빠르고 단순합니다.

DataStore 장점 표

간단하게 특징을 요약한다면

  • DataStore는 코투린과 Flow를 통해 읽고 쓰기에 대한 비동기 API를 제공합니다.
  • DataStore는 UI 스레드를 호출해도 안전합니다.(Dispather.IO 아래에서 작동을 하기 때문입니다.)
  • runtime exception으로부터 안전합니다.

DataStore의 생성

class DataStoreModule(private val context : Context) {
	private val Context.dataStore by
    preferencesDataStore(name = "dataStore")
    
    private val stringKey = stringPreferencesKey("key_name")
    private val intkey = intPreferencesKey("key_name")
    ...
}

먼저 globalDataStore속성을 통하여 DataStore를 생성합니다.

이렇게 DataStore를 생성하고 난 뒤에는 저장할 값의 키들을 생성해줍니다. 키값의 경우 'type'PreferencesKey("name")으로 생성을 해주면 됩니다.

DataStore에서 값 읽기

DataStore에서는 데이터를 읽을 떄 데이터는 Flow 객체로 전달이 되기에 다음과 같이 사용합니다.

    val text : Flow<String> = context.dataStore.data
        .catch { exception ->
            if (exception is IOException) {
                emit(emptyPreferences())
            } else {
                throw exception
            }
        }
        .map {preferences ->
            preferences[stringKey] ?: ""
        }

map()을 이용해서 DataStore에 저장되어 있는 값을 미리 지정해둔 키를 통해 가져옵니다. 이때 반환되는 값은 Flow 타입입니다. 또한 작업에 실패하였을 때를 대비에 catch()문으로 exception을 조건을 해줍니다.

DataStore에 값 쓰기

DataStore의 값을 쓸때는 edit()를 이용합니다. DataStore에 값을 작성하기 위해서는 반드시 비동기로 동작해야하기에 suspend를 이용합니다.

suspend fun setText(text : String){
	context.dataStore.edit { preferences ->
    	preferences[stringKey] = text
        }
    }

DataStore 사용하기

class SampleApplication : Application() {

    private lateinit var dataStore : DataStoreModule

    companion object {
        private lateinit var sampleApplication: SampleApplication
        fun getInstance() : SampleApplication = sampleApplication
    }

    override fun onCreate() {
        super.onCreate()
        sampleApplication = this
        dataStore = DataStoreModule(this)
    }

    fun getDataStore() : DataStoreModule = dataStore
}

DataStore는 Singleton으로 관리되어야하기에 Application에서 생성하고 사용합니다.

Activity/ Fragment 값 읽고 쓰기

읽기의 경우 선언해 놓은 변수에 접근한 후 Flow객체를 반환 받고 collect()를 이용하여 값을 읽어옵니다.

SampleApplication.getInstance().getDataStore().text.collect {
	it -> //... do it Something

DataStore는 Flow형태로 값을 받아오기 때문에 값 변경이 있어야만 동작을 하게됩니다. 동작의 변경이 아닌 원하는 타이밍에 값을 가져오고 싶다면 first()함수를 이용해 값을 호출할 수 있습니다.

val text = SampleApplication.getInstance().getDataStore().
text.first()

DataStore에 값을 저장하고 싶을때는 DataClass에 미리 작성해 놓은 함수를 호출하면됩니다. 비동기 작업이기에 코루틴이나 RxJava로 호출해주면 됩니다.

CoroutineScope(Dispatchers.Main).launch {
	val text = "Simple"
    SampleApplication.getInstance().getDataStore().
    setText(text)
}

SharedPreferences를 대체하기 위해 등장한 만큼 많은 장점을 가지고 있습니다. 특히 Coroutine Flow를 자체적으로 지원해주다 보니 훨씬 비동기적이고 안전한 Read & Wrtie 동작을 할 수 있는 것이 가장 큰 장점이라고 할 수 있습니다.

references

https://developer.android.com/topic/libraries/architecture/datastore?hl=ko

profile
Android 개발 잘하고 싶어요!!!

0개의 댓글