[Android] DataStore μ–΄μ„œμ˜€κ³ πŸ‘‹

μž„μž¬μ˜Β·2021λ…„ 10μ›” 1일
0

Android

λͺ©λ‘ 보기
8/10
post-thumbnail

DataStore?

  • Protocol Bufferλ₯Ό μ‚¬μš©ν•˜μ—¬ Key-Valueλ°μ΄ν„°λ‚˜ Typed Objectsλ₯Ό μ €μž₯ν•  수 μžˆλ‹€.

  • DataStoreλŠ” Coroutine + Flowλ₯Ό μ‚¬μš©ν•˜μ—¬ 비동기적이고 일관적인 νŠΈλžœμž­μ…˜ λ°©μ‹μœΌλ‘œ 데이터λ₯Ό μ €μž₯ν•œλ‹€.

  • DataStoreλŠ” Preferences DataStoreκ³Ό Proto DataStore 두 κ°€μ§€λ‘œ λΆ„λ₯˜λœλ‹€.

  • SharedPreferencesλ₯Ό λŒ€μ²΄ν•˜λŠ” μƒˆλ‘œμš΄ 데이터 μ €μž₯μˆ˜λ‹¨μ΄λ‹€.


DataStoreκ³Ό SharedPreference

DataStoreκ³Ό SharedPreferenceλ₯Ό λΉ„κ΅ν•˜λ©΄ μœ„μ™€ κ°™λ‹€.

μœ„ λ‚΄μš©μ„ μš”μ•½ν•˜μžλ©΄,

  • Flowλ₯Ό μ‚¬μš©ν•˜μ—¬ I/O에 λŒ€ν•œ 비동기 μ²˜λ¦¬κ°€ κ°€λŠ₯.
  • Dispatcher.IO ν•˜μœ„μ—μ„œ λ™μž‘ν•˜μ—¬ MainThreadμ—μ„œ ν˜ΈμΆœλ˜μ–΄λ„ μ•ˆμ „ν•¨.
  • RuntimeExceptionμœΌλ‘œλΆ€ν„° μ•ˆμ „ν•¨

이젠 더 이상 SharedPreference의 μ‚¬μš©μ„ 고집 ν•  ν•„μš”κ°€ 없을 것 κ°™λ‹€.


DataStore μ‚¬μš© 방법

μ˜μ‘΄μ„± μΆ”κ°€

μ•±λͺ¨λ“ˆμ˜ build.gradle에 λ‹€μŒ λ‚΄μš© μΆ”κ°€

dependencies {
    implementation("androidx.datastore:datastore-preferences:1.0.0")
    implementation("androidx.datastore:datastore-preferences-core:1.0.0")
}

DataStore 객체 생성

class DataStoreModule(private val context: Context) {
    private val Context.dataStore by preferencesDataStore(name = "dataStore")

    private val myStringKey = stringPreferencesKey("keyName") 
    private val myIntKey = intPreferencesKey("keyName") 
}

DataStoreμ—μ„œ μ‚¬μš©ν•˜λŠ” ν‚€ 값은 μ‚¬μš©ν• νƒ€μž…PreferencesKey("keyName")κ³Ό 같은 ν˜•νƒœλ‘œ μ„ μ–Έ ν•  수 μžˆλ‹€. μœ„μ˜ μ˜ˆμ‹œλŠ” 각각 string int νƒ€μž…μ˜ 데이터λ₯Ό μ €μž₯ν•˜κΈ° μœ„ν•œ μ˜ˆμ‹œμ΄λ‹€.


Dataλ₯Ό μ½λŠ” Flow λ§Œλ“€κΈ°

μ½”λ£¨ν‹΄μ˜ Flowλ₯Ό μ‚¬μš©ν•˜μ—¬ DataStoreμ—μ„œ 데이터λ₯Ό μ½μ–΄μ˜¬ λ•Œ ν•΄λ‹Ή 데이터λ₯Ό Flow객체둜 μ „λ‹¬ν•œλ‹€.

// μœ„μ—μ„œ λ§Œλ“  `myStringKey` Key 값에 λŒ€μ‘ν•˜λŠ” Value λ°˜ν™˜
val textData: Flow<String> =
    context.dataStore.data
        .catch { exception ->
            if (exception is IOException) {
                emit(emptyPreferences())
            } else {
                throw exception
            }
        }
        .map { preferences ->
            preferences[myStringKey] ?: ""  // μœ„μ—μ„œ λ§Œλ“  Key
        }
  • map()을 ν™œμš©ν•˜μ—¬ myStringKey에 λŒ€μ‘ν•˜λŠ” Valueλ₯Ό Flow ν˜•νƒœλ‘œ κ°€μ Έμ˜€κ²Œ λœλ‹€.

  • catch()λ₯Ό μ‚¬μš©ν•˜μ—¬ 데이터 μ½λŠ” κ³Όμ •μ—μ„œ λ¬Έμ œκ°€ 생겼을 λ•Œ μ˜ˆμ™Έμ²˜λ¦¬λ₯Ό 해쀄 수 μžˆλ‹€.


데이터 κ°€μ Έμ˜€κΈ°

DataStoreμ—μ„œ 읽은 데이터λ₯Ό TextView에 μ μš©ν•΄λ³΄λ„λ‘ν•œλ‹€. (λ‹€μŒ μž‘μ—…μ€ CoroutineScope λ‚΄μ—μ„œ μˆ˜ν–‰λ˜μ–΄μ•Όν•œλ‹€.)

CoroutineScope(Dispatchers.Main).launch {
    MyApplication.getInstance().getDataStore().textData.collect {
        textView.text = it
    }
}

데이터 μ €μž₯ν•˜κΈ°

데이터λ₯Ό μ“°κΈ° μœ„ν•΄μ„  edit()λ₯Ό μ‚¬μš©ν•œλ‹€. ν•΄λ‹Ή μž‘μ—…μ€ λΉ„λ™κΈ°μ μœΌλ‘œ λ™μž‘ν•˜λ―€λ‘œ suspend ν‚€μ›Œλ“œλ₯Ό 톡해 코루틴 μ˜μ—­μ—μ„œ λ™μž‘ν•  수 μžˆλ„λ‘ ν•œλ‹€.

// String 값을 `stringKey` 의 Value 둜 μ €μž₯
suspend fun setTextData(text: String) {
    context.dataStore.edit { preferences ->
        preferences[stringKey] = text  // μ•„κΉŒ λ§Œλ“  Key 이용
    }
}

μœ„μ™€ 같이 데이터λ₯Ό μ“°κΈ° μœ„ν•œ suspend ν•¨μˆ˜λ₯Ό λ§Œλ“€μ—ˆλ‹€λ©΄, λ‹€μŒκ³Ό 같이 ν˜ΈμΆœν•˜μ—¬ μ‚¬μš© ν•  수 μžˆλ‹€.

CoroutineScope(Dispatchers.Main).launch {
    MyApplication.getInstance().getDataStore().setTextData("H43RO")
}

DataStoreλ₯Ό μ‚¬μš©ν•˜λ©΄μ„œ 비동기 μ²˜λ¦¬κ°€ μ•„λ‹Œ 동기 처리λ₯Ό ν•˜κ³  μ‹Άλ‹€λ©΄, λ‹€μŒμ™€ 같이 μ‚¬μš© ν•  수 μžˆλ‹€.

runBlocking {
   val text = MyApplication.getInstance().getDataStore().textData.first()
}

λ‹€λ§Œ, runBlocking μ•ˆμ—μ„œ 무거운 μž‘μ—…μ€ ν”Όν•΄μ•Όν•œλ‹€. λΈ”λ‘œν‚Ή λ˜λŠ” μ‹œκ°„μ΄ 길어짐에 따라 ν”„λ ˆμž„ λ“œλžμœΌλ‘œ μΈν•œ ν™”λ©΄ λ²„λ²…μž„(16ms), ANR(5s)둜 μ΄μ–΄μ§ˆ 수 μžˆλ‹€.


κ²°λ‘ 

μ•žμœΌλ‘  SharedPreference λŒ€μ‹  DataStoreλ₯Ό μ‚¬μš©ν•˜μž


참고자료

https://android-developers.googleblog.com/2020/09/prefer-storing-data-with-jetpack.html

https://developer.android.com/topic/libraries/architecture/datastore?gclid=Cj0KCQjwqKuKBhCxARIsACf4XuHSV6c0dQKCbCAO0rH42Pc-MFbVKxhgf1YRYxu2qf_yPmkeU5m3WfoaAqfKEALw_wcB&gclsrc=aw.ds#kts

https://android-developers.googleblog.com/2020/09/prefer-storing-data-with-jetpack.html

https://velog.io/@haero_kim/Android-DataStore-%EC%B2%AB-%EC%9D%B8%EC%83%81-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0

profile
μ–΄μ œμ˜ λ‚˜λ³΄λ‹€ 더 λ‚˜μ€ μ‚¬λžŒμ΄ 되자

1개의 λŒ“κΈ€

comment-user-thumbnail
2021λ…„ 10μ›” 1일

λ°μ΄ν„°μŠ€ν† μ–΄ κ°€μ¦ˆμ•„!! πŸš€

λ‹΅κΈ€ 달기