๋ชฉ์ฐจ
๋์ ๋ฐฐ๊ฒฝ
ํ๋ก์ ํธ์์ ์ธํ์นด๋์ ์ถฉ์ ํ ๊ธ์ก์ ์ ๋ ฅํ๋ฉด ์์ผ๋ก ๋จ์ ์ธํ ํ์์ ๋จ์ ์์ก์ ํ์ธ ํ ์ ์๋ ํ๋ฉด์ ๊ตฌํํ๊ณ ์๋ค.
์ด ๋ ๊ฐ ์ฌ์ฉ์์ ์์ก์ ๋ก์ปฌ db์ ์ ์ฅํ๊ธฐ ์ํด ์๋ ๋ก์ปฌ db๋ก์ ์ผ๋ฐ์ ์ผ๋ก ์๊ณ ์๋ shared prefereces๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด ์๋ฃ๋ฅผ ์ฐพ์๋ณด๋ ์ค! preferences datastore์ proto datastore์ด๋ผ๋ ๋ฐ์ดํฐ ์ ์ฅ ๋ฐฉ๋ฒ์ด ์๋ค๋ ๊ฒ๊ณผ
์ด ๋ฐฉ๋ฒ์ด shared preferences์ ๋จ์ ์ ๊ทน๋ณตํ๊ธฐ ์ํด ๋์๋ค๋ ๊ฒ์ ์๊ฒ ๋์๋ค.
๋ฐ๋ผ์ shared preferences๋ฅผ ๋ณด์ํ preferences datastore์ ํ๋ก์ ํธ์ ์ ์ฉํ๊ธฐ๋ก ๊ฒฐ์ ํ๋ค.
๊ฐ๋ ์ดํดํ๊ธฐ
datastore์ ๊ฐ์ ๋ ์ ๊ท ๋ฐ์ดํฐ ์ ์ฅ์ ์๋ฃจ์ ์ผ๋ก ์ฐ๋ฆฌ๊ฐ ์๊ณ ์๋ shared preferences๋ฅผ ๋์ฒดํ๋ ๋ฐฉ๋ฒ์ด๋ค!!
kotlin ์ฝ๋ฃจํด๊ณผ Flow๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ์ฌ ๋ ๊ฐ์ง ์ข ๋ฅ๊ฐ ์กด์ฌํ๋๋ฐ ์ฒซ ๋ฒ์งธ๋ ํ์ ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๋ proto datastore์ด๊ณ , ๋๋ฒ์งธ๋ ํค-๊ฐ ์์ ์ ์ฅํ๋ preferences datastore์ด๋ค.
์ฌ์ฉํ๋ ค๋ preferences datastore์ ๋ก๊ทธ์ธ ์ธ๋ถ ์ ๋ณด ์ ์ฅ์ด๋ ์ด๋์ด ๋ชจ๋ ์ค์ , ๊ธ๊ผด ํฌ๊ธฐ ๋ฑ ์๊ณ ๊ฐ๋จํ ๋ฐ์ดํฐ ์ธํธ์ ์ ํฉํ๋ค. Datastore๋ ์จ๋ผ์ธ ์๋ฃํ์ ์ธ๋ฒคํ ๋ฆฌ ๋ชฉ๋ก์ด๋ ํ์ ๋ฐ์ดํฐ ๋ฒ ์ด์ค์ ๊ฐ์ ๋ณต์กํ ๋ฐ์ดํฐ ์ธํธ์๋ ์ ํฉํ์ง ์๋ค. ๋์ฉ๋ ๋๋ ๋ณต์กํ ๋ฐ์ดํฐ ์ธํธ๋ฅผ ์ ์ฅํด์ผํ๋ค๋ฉด Datastore ๋์ room ์ฌ์ฉ์ ๊ถ์ฅํ๊ณ ์๋ค
๋ด๊ฐ ์ ์ฅํ๊ณ ์ ํ๋ ๋ฐ์ดํฐ๋ ๋จ์ ๊ธ์ก์ผ๋ก ๊ฐ๋จํ ๋ฐ์ดํฐ์ด๋ค. ๋ฐ๋ผ์ datastore ์ค preference datastore๊ฐ ๋ ์ ํฉํ ๋ฐฉ์์ด๋ผ๊ณ ์๊ฐํ๋ค.
๋ก์ง ์ดํดํ๊ธฐ
[ ๋ก์ง ]
์ฌ์ฉ์๊ฐ ์ธํ ์นด๋์ ์ถฉ์ ํ ๊ธ์ก์ ๊ธฐ๋กํ๋ฉด ํ๋ฉด์ ๋จ์ ๊ธ์ก์ ์ถฉ์ ํ ๊ธ์ก์ด ํฉํด์ง ๊ธ์ก์ด ๋ณด์ฌ์ง๋ค.
์ด ๋ ๋จ์ ๊ธ์ก์ ์ฌ์ฉ์์ ๋ก์ปฌ์ ์ ์ฅ๋์ด์ ์ฑ์ ๋๊ณ ๋ค์ ์คํํด๋ ๋จ์์์ด์ผํ๋ค.
์ธํ์นด๋์ ๋จ์ ๊ธ์ก์ ์ ์ฅํ๊ธฐ ์ํด ๋ทฐ๋ชจ๋ธ๊ณผ preferences datastore์ ์ด์ฉํด๋ณด์๋ค.
[์์]
1. Datastore ๋ง๋ค๊ธฐ
2. PreferencesKeys ์ ์
3. ์ถฉ์ ๊ธ์ก์ ๋ํ Flow ์์ฑ
4. ์ถฉ์ ๊ธ์ก ์ ์ฅ
5. ViewModel์์ ์ถฉ์ ๊ธ์ก ์ ๋ฐ์ดํธ
1.Preferences Datastore ๋ง๋ค๊ธฐ
// Datestore ๋ง๋ค๊ธฐ
private const val PREFERENCES_NAME = "user_preferences"
// Create a DataStore instance using the preferencesDataStore delegate, with the Context as
// receiver.
val Context.dataStore : DataStore<Preferences> by preferencesDataStore(name = PREFERENCES_NAME)
"user_preferences" ๋ ์ธ์คํด์คํํ preferences datastore์ ์ด๋ฆ์ด๋ค.
preferencesDataStore ์์์ ์ฌ์ฉํ์ฌ "user_preferences" ๋ผ๋ ์ด๋ฆ์ DataStore ์ธ์คํด์ค๋ฅผ ๋ง๋ ๋ค.
Context๋ receiver ์ญํ ์ด๋ผ๊ณ ํ๋ค!
kotlin ํ์ผ์ ์ต์์ ์์ค์์ DataStore ์ธ์คํด์ค๋ฅผ ํ๋ฒ ๋ง๋ค๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋จธ์ง ๋ถ๋ถ์์ ์ด ์์ฑ์ ํตํด ์ธ์คํด์ค์ ์ก์ธ์คํ๋ ๊ฒ์ด ์ข๋ค๊ณ ํ๋ค. ์ด๋ ๊ฒ ํ๋ฉด DataStore์ ์ฑ๊ธํค์ผ๋ก ์ ์งํ ์ ์๋ค.
DataStore ์ธ์คํด์ค๊ฐ ์ฌ๋ฌ ๊ฐ ๋ง๋ค์ด์ง ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ฑ๊ธํค์ ์ฌ์ฉํ๋ค
2. PreferencesKeys ์ ์
private object PreferencesKeys {
val CHARGED_MONEY = intPreferencesKey("charged_money")
}
intPreferencesKey๋ฅผ ์ฌ์ฉํ์ฌ "charged_money" ๋ผ๋ ํค๋ฅผ ์ ์ํ๋ค. ์ด ํค๋ ๋ฐ์ดํฐ ์คํ ์ด์์ ์ ์๊ฐ์ ์ ์ฅํ๊ณ ๊ฒ์ํ๋๋ฐ ์ฌ์ฉ๋๋ค.
preferences datastore์ ์ฌ์ ์ ์๋ ์คํค๋ง๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค.
DataStore<Preferences> ์ธ์คํด์ค์ ์ ์ฅํด์ผํ๋ ๊ฐ ๊ฐ์ ํค๋ฅผ ์ ์ํ๋ ค๋ฉด ๊ฑฐ๊ธฐ์ ๋ง๋ ํค ์ ํ ํจ์๋ฅผ ์ฌ์ฉํด์ผํ๋ค. ๋๋ ๋จ์ ๊ธ์ก์ด๋ผ๋ Intํ ๊ฐ์ ํค๋ฅผ ์ ์ํ๊ณ ์ ํ์ผ๋ฏ๋ก intPreferenceKey( )๋ฅผ ์ฌ์ฉํ์๋ค.
๊ทธ ํ DataStore.data ์์ฑ์ ์ฌ์ฉํ์ฌ Flow๋ฅผ ์ฌ์ฉํ ์ ์ ํ ์ ์ฅ ๊ฐ์ ๋ ธ์ถํ๋ค.
3. ์ถฉ์ ๊ธ์ก์ ๋ํ Flow ์์ฑ : Preferences Datastore์์ ์ฝ๊ธฐ
val chargedMoneyFlow: Flow<Int> = dataStore.data
.catch {
exception -> if (exception is IOException) {
emit(emptyPreferences())
} else{
throw exception
}
}
.map { preferences ->
preferences[PreferencesKeys.CHARGED_MONEY] ?: 0 }
dataStore.data ์์ฑ์ datastore์์ ๋ฐ์ดํฐ๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ๊ฐ์ ์ค๊ธฐ ์ํด Flow๋ฅผ ์ ๊ณตํด์ค๋ค.
์ด Flow๋ฅผ ํตํด ์ฑ์ ์ฌ๋ฌ ๋ถ๋ถ ์์ ๋ฐ์ดํฐ๋ฅผ ๊ด์ฐฐํ๊ณ ์ฌ์ฉํ ์ ์๋ค.
dataStore.data๋ datastore์ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ฅผ Flow์ ๋ ธ์ถํด์ค๋ค.
datasotre ๊ฐ์ฒด๋ Preferences DataStore์ ๋ํ๋ธ๋ค.
.data๋ ๋ฐ์ดํฐ์คํ ์ด์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ๋ ๋ฐ ์ฌ์ฉ๋๋ ์์ฑ์ด๋ค.
* chargedMoneyFlow๋ ๋ฐ์ดํฐ ์คํ ์ด์ ์ ์ฅ๋ ์ถฉ์ ๊ธ์ก ๊ฐ์ ๋ฐฉ์ถํ๋ Flow์ด๋ค.
* .catch๋ ์์ธ ์ฒ๋ฆฌ๋ฅผ ์ํด ์์ฑํด์ฃผ์๊ณ , IOException์ด ๋ฐ์ํ ๊ฒฝ์ฐ ๋น preference๋ฅผ ๋ฐฉ์ถํ๋ค.
* .map์
preferece๋ฅผ ์ค์ ์ถฉ์ ๊ธ์ก ๊ฐ์ผ๋ก ๋ฐํํด์ค๋ค.
Flow์ ๊ฐ ์ด๋ฒคํธ์ ๋ํ ๋ณํ์ ์ํํ๋ค. preferences๋ Flow์์ ๋ฐ์์จ Preferences ๋ฐ์ดํฐ์ด๋ค.
preferences[PreferencesKeys.CHARGED_MONEY] ?: 0 ์ CHARGED_MONEY ํค์ ํด๋นํ๋ ๊ฐ์ ์ฝ์ด์ค๋๋ฐ ์ด ๋ ๊ฐ์ด null์ด๋ฉด 0์ผ๋ก ๋์ฒดํด์ค๋ค.
๋ฐ๋ผ์ chargedMoneyFlow๋ฅผ subscribeํ๋ฉด ๋ก์ปฌ ๋ฐ์ดํฐ ์คํ ์ด์ ์ ์ฅ๋ ์ถฉ์ ๊ธ์ก์ ๋น๋๊ธฐ์ ์ผ๋ก ๊ฐ์ํ ์ ์๋ค. ์ด Flow๋ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค ํด๋น ๋ณ๊ฒฝ์ฌํญ์ ์ ์ฉํ ์ ์๋ค.
4. ์ถฉ์ ๊ธ์ก ์ ์ฅํ๊ธฐ : Prefereces DataStore์ ์ฐ๊ธฐ
private suspend fun saveChargedMoney(value: Int) {
dataStore.edit { preferences ->
preferences[PreferencesKeys.CHARGED_MONEY] = value
}
}
Preferences Datastore์ Datastore์ ๋ฐ์ดํฐ๋ฅผ ํธ๋์ญ์ ๋ฐฉ์์ผ๋ก ์ ๋ฐ์ดํธํ๋ edit ( ) ํจ์๋ฅผ ์ ๊ณตํ๋ค.
edit ํจ์๋ฅผ ํตํด ๋ฐ์ดํฐ ์คํ ์ด๋ฅผ ์์ ํ๋ค.
ํธ๋์ญ์ ๋ฐฉ์?
ํธ๋์ญ์ ๋ฐฉ์์ด๋
์ฌ๋ฌ ์ฐ์ฐ์ ๋ฌถ์ด์ ์ผ๊ด์ ์ผ๋ก ์ฒ๋ฆฌํ๊ณ ์ด ๊ณผ์ ์์ ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ๋ณด์ฅํ๋ ๋งค์ปค๋์ฆ์ ์๋ฏธํ๋ค.
DataStore์ edit ํจ์์ ํน์ง 4๊ฐ์ง
1. ์์์ฑ(atomicity) : edit ํจ์ ๋ด์์ ์ํ๋๋ ๋ชจ๋ ๋ณ๊ฒฝ ์ฌํญ์ ์์์ ์ผ๋ก ์ฒ๋ฆฌ๋๋ค. ์ฆ ๋ชจ๋ ๋ณ๊ฒฝ์ด ์ฑ๊ณตํ๊ฑฐ๋ ์คํจํ๋ ๊ฒ์ ๋ณด์ฅํ๋ค.
์๋ฅผ ๋ค์ด ์ฌ๋ฌ ๊ฐ์ key-value ์์ ๋ณ๊ฒฝํ๋๋ผ๋ ๋ชจ๋ ๋ณ๊ฒฝ์ด ์ฑ๊ณตํ๊ฑฐ๋ ์๋ฌด๊ฒ๋ ๋ณ๊ฒฝ๋์ง ์๋ ๊ฒ์ด๋ค.
2. ๋ฐ์ดํฐ ๋ถ์ผ์น ๋ฐฉ์ง : edit ํจ์๋ datastore์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ฒ ์์ ํ๋๋ก ํด์ค๋ค. ์ฌ๋ฌ ์ค๋ ๋ ๋๋ ์ฝ๋ฃจํด์ด ๋์์ datastore์ ์์ ํ๋ ค๊ณ ํ ๋ ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ์ ์งํ๋๋ก ํ๋ค.
3. ๋กค๋ฐฑ : edit ํจ์ ๋ด์์ ๋ณ๊ฒฝ์ฌํญ์ ์ ์ฉํ๋ ๋์ค์ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด ๋ชจ๋ ๋ณ๊ฒฝ์ฌํญ์ด ๋กค๋ฐฑ๋์ด ์ด์ ์ํ๋ก ๋์๊ฐ๋ค. ์ด๋ ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ์ ์งํ๊ณ ์ค๋ฅ ์ํ์์๋ ์์ธก ๊ฐ๋ฅํ ์ํ๋ก ๋ณต๊ตฌํ ์ ์๋๋ก ํ๋ค.
Datastor<Preferences>์์ ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝ๋ ๋ ์ฌ์ฉ๋๋ edit ํจ์๋ ์๋์ ๊ฐ์ด ์ ์๋์ด์๋ค.
public suspend fun DataStore<Preferences>.edit(
transform: suspend (MutablePreferences) -> Unit
): Preferences {
return this.updateData {
// It's safe to return MutablePreferences since we freeze it in
// PreferencesDataStore.updateData()
it.toMutablePreferences().apply { transform(this) }
}
}
์ฝ๋ ์ค๋ช
tranform : suspend (MutablePreferences) -> Unit : ์ด ํจ์๋ MutablePreferences๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์๋ค์ด๋ ๋๋คํจ์์ด๋ค.
MutablePreferences๋ ์์ ๊ฐ๋ฅํ ํํ์ Prefereces๋ฅผ ๋ํ๋ธ๋ค.
suspend ํค์๋๋ ์ด ํจ์๊ฐ ์ฝ๋ฃจํด์ผ๋ก ๋์๊ฐ๋ฅํจ์ ์๋ฏธ!
์ฌ๊ธฐ์ tranform ๋งค๊ฐ๋ณ์๋ ํ์์ ๋ฐ๋ผ ๊ฐ์ ์ ๋ฐ์ดํธํ ์ ์๋ ์ฝ๋ ๋ธ๋ก์ ํ์ฉํ๋ค. ๋ณํ ๋ธ๋ก์ ๋ชจ๋ ์ฝ๋๋ ๋จ์ผ ํธ๋์ญ์ ์ผ๋ก ์ทจ๊ธ๋๋ค.
this.updateData ๋ถ๋ถ์ DataStore์์ ์ ๊ณตํ๋ ๋ค๋ฅธ ํจ์์ธ updateData๋ฅผ ํธ์ถํ๋ค. ์ด ํจ์๋ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฐ์ดํธํ๊ณ ์ ๋ฐ์ดํธ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ค.
it.toMutablePreference( ).apply { transform(this) }๋ updateDataํจ์ ๋ด์์ ์๋ก์ด MutablePrefereces๋ฅผ ๋ง๋ค๊ณ ์ด๋ฅผ ๋๋ค ํจ์ transform์ ์ ๋ฌํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ๋ค.
return this.updateData {...} ๋ ์ ๋ฐ์ดํธ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ค. ์ด๋ edit ํจ์๋ฅผ ํธ์ถํ ์ชฝ์์ ์ ๋ฐ์ดํธ๋ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ํด์ค๋ค.
์ ๋ฆฌํ๋ฉด
์ด edit ํจ์๋ DataStor์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ธฐ ์ํ ๋๋คํจ์ transform์ ์ฌ์ฉํ๊ณ ์์ ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ค.
์ฐ๋ฆฌ ์ฝ๋ ๋ค์ ๋ณด๊ธฐ
private suspend fun saveChargedMoney(value:Int) {
dataStore.edit { preferences ->
preferences[PreferencesKeys.CHARGED_MONEY] = value }
}
์ฐ๋ฆฌ์ ์ฝ๋์์๋ dataStore.edit ํจ์์ ๋๋ค ํ๋ผ๋ฏธํฐ๋ preferences์ด๋ค. ๋ฐ๋ผ์ ์ด preferences๊ฐ tranform ์ญํ ์ ํ๋ค.
preferences๋ MutablePrefereces์ ์ธ์คํด์ค๋ก ์์ ๊ฐ๋ฅํ Preferences๋ฅผ ๋ํ๋ธ๋ค.
preferences[PreferencesKeys.CHARGED_MONEY] = value ์ฝ๋๋ MutablePreferences๋ฅผ ํตํด CHARGED_MONEY ํค์ ๋ํ ๊ฐ์ value๋ก ๋ณ๊ฒฝํ๋ ์ญํ ์ ํ๋ค.
5. ViewModel์์ ์ถฉ์ ๊ธ์ก ์ ๋ฐ์ดํธ
var chargedMoney by mutableIntStateOf(0)
private set
fun updateChargedMoney(input: Int) {
viewModelScope.launch {
chargedMoney += input
saveChargedMoney(chargedMoney)
}
}
updateChargedMoney ํจ์๋ input ๋งํผ chargeMoney์ ํฉํด์ฃผ์ด ์ ๋ฐ์ดํธ๋ฅผ ํด์ค ํ ๋ณ๊ฒฝ๋ chargeMoney๋ฅผ ๋ฐ์ดํฐ ์คํ ์ด์ ๋ค์ ์ ์ฅํด์ค๋ค.
๐จ ๋ฌธ์ ๋ฐ์ : ์ฑ์ด ๊บผ์ง๊ณ ๋ค์ ์คํ๋ ๊ฒฝ์ฐ ๋๋ ๋ค๋น๊ฒ์ด์ ํ ๋ค์ ์ถฉ์ ํ ๊ฒฝ์ฐ ๊ธฐ์กด์ ๊ธ์ก์ ์ฑ์ด ๊ธ์ก๋งํผ ๋ํด์ง์ง ์๊ณ 0์ผ๋ก ์ด๊ธฐํ๋์ด์ ์ฑ์ด ๊ธ์ก๋งํผ์ด ๋ํด์ง๋ค.
๋ค์ ํฌ์คํ ์์๋ ๋ทฐ๋ชจ๋ธ๊ณผ ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ๊ณผ์ ์ ๊ธฐ๋กํด๋ณผ์์ ์ด๋ค!
'๐ค2024 ์๋๋ก์ด๋ > ๊ธฐ์์ฌ ํ๋ก์ ํธ ๊ธฐ๋ก' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Compose์์ ๊ตฌ์ฑ๋ณ๊ฒฝ ์ ์ ์ฅ๋์ง ์๋ ๋ฌธ์ ํด๊ฒฐํ๊ธฐ (2) | 2024.01.21 |
---|---|
android Flow ์์๋ณด๊ธฐ (2) | 2024.01.21 |
kotlin coroutines basic ๊ณต์๋ฌธ์ ์ฝ์ด๋ณด๊ธฐ (0) | 2024.01.17 |
๐ Android FCM ์ ์ฉ๊ธฐ 2ํ : FCM + Retrofit (0) | 2024.01.07 |
๐Android FCM ์ ์ฉ๊ธฐ 1ํ : Notification ํํค์ณ๋ณด๊ธฐ (1) | 2024.01.06 |