Jetpack Compose - DataStore<Preferences>

2024. 3. 20. 15:51IT/Android

728x90

<미리 보기>

앱을 종료해도 레이아웃의 정보가 저장된다.

 

 

 

<소스 코드>

https://github.com/SeongHyunJeon/android-kotlin-practice/tree/85a03144de512562d0e2807e1d78e9867ff28aac/Dessert%20Release

 

 

 

<정리>

DataStore - 관계형 데이터를 저장할 필요가 없는 경우 사용할 수 있는 경량 데이터 저장 솔루션으로, 두 가지 주요 구현체를 제공한다.

1. Preference DataStore: 키-값 쌍의 데이터를 저장하고 일반적으로 사용자 정의 타입이 아닌 Kotlin 기본 데이터 타입을 갖는다. 레이아웃, 다크 모드와 같은 간단한 앱의 사용자 환경 설정 값을 기기에 저장할 때 고려할 수 있다.

2. Proto DataStore: 맞춤 데이터 유형을 저장하고 proto 정의를 객체 구조로 매핑하는 사전 정의된 스키마를 필요로 한다.

 

DataStore<Preferences>객체를 파라미터로 받아 연산을 정의하는 저장소.

class UserPreferencesRepository(
    private val dataStore: DataStore<Preferences>
) {
    /**
     * booleanPreferencesKey():
     * 불리언 타입의 키를 생성한다. <저장될 값과 동일한 타입의 키를 생성해야 한다.>
     * 이름은 언더바와 소문자로 이루어진 문자열이 권장된다.
     * 해당 키를 활용하여 DataStore의 값을 읽고 저장할 수 있다.
     */
    private companion object {
        val IS_LINEAR_LAYOUT = booleanPreferencesKey("is_linear_layout")
        const val TAG = "UserPreferencesRepo" //예외를 위한 로그 메세지.
    }

    /**
     * DataStore<Preferences>.edit():
     * DataStore의 값을 변경하는 메서드.
     * 해당 람다에 선언된 작업들은 순차적으로 실행되는데 하나라도 실패하면 이전에 실행된 모든 게 롤백되어 변경사항이 적용되지 않는 단일 트랜잭션으로 실행된다.
     * 해당 함수가 호출되어 값이 저장되면 앱의 캐시나 데이터를 따로 삭제하지 않는 한 영구적으로 보존된다.
     */
    suspend fun saveLayoutPreference(isLinearLayout: Boolean) {
        dataStore.edit { preferences ->
            preferences[IS_LINEAR_LAYOUT] = isLinearLayout //키를 사용하여 파라미터로 받은 값을 DataStore에 저장한다.
        }
    }

    /**
     * DataStore<Preferences>.data:
     * DataStore의 값을 읽는 프로퍼타로, 파일로부터 데이터를 읽어오기 때문에 IOException 예외가 발생할 수 있다.
     * Flow<Preferences>를 반환하므로 데이터의 수집/방출이 가능하다.
     */
    val isLinearLayout: Flow<Boolean> = dataStore.data
        .catch {
            if(it is IOException) {
                Log.e(TAG, "Error reading preferences.", it)
                emit(emptyPreferences()) //비어 있는 Preferences 반환.
            } else {
                throw it
            }
        }
        .map { preferences ->
            preferences[IS_LINEAR_LAYOUT] ?: true //매칭되는 키가 없으면 널을 반환하므로 기본 값을 설정하는 것이 좋다.
        } // Flow<Preferences> -> Flow<Boolean> 변환.
}

 

저장소 객체를 생성하는 Application 클래스.

private const val LAYOUT_PREFERENCE_NAME = "layout_preferences"
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(
    name = LAYOUT_PREFERENCE_NAME
) //DataStore<Preferences> 객체 생성.

class DessertReleaseApplication: Application() {
    lateinit var userPreferencesRepository: UserPreferencesRepository

    override fun onCreate() {
        super.onCreate()
        userPreferencesRepository = UserPreferencesRepository(dataStore)
    }
}

 

*Preferences 컴파일 에러가 발생한다면, import한 라이브러리가 아래와 동일한지 확인 할 필요가 있다.

androidx.datastore.preferences.core.Preferences

LazyVerticalGrid의 verticalArrangement, horizontalArrangement 프로퍼티에 Arrangement.spacedBy()를 적용하면 각 항목들의 가로, 세로 간격을 한 번에 적용할 수 있다.

 

Text의 수정자 modifier를 이용한 설정에서 wrapContentHeight()의 파라미터로 Alignment.CenterVertically을 전달하면 wrapContentHeight()이 적용되기 전의 높이를 기준으로 수직 가운데 정렬이 가능하다.

LazyVerticalGrid(
    modifier = modifier,
    columns = GridCells.Fixed(3),
    contentPadding = contentPadding,
    verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_medium)),
    horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_medium))
) {
    items(
        items = LocalDessertReleaseData.dessertReleases,
        key = { dessert -> dessert }
    ) { dessert ->
        Card(
            colors = CardDefaults.cardColors(
                containerColor = MaterialTheme.colorScheme.primary
            ),
            modifier = Modifier.height(110.dp),
            shape = MaterialTheme.shapes.medium
        ) {
            Text(
                text = dessert,
                maxLines = 2,
                overflow = TextOverflow.Ellipsis,
                modifier = Modifier
                    .fillMaxHeight()
                    .wrapContentHeight(Alignment.CenterVertically)
                    .padding(dimensionResource(R.dimen.padding_small))
                    .align(Alignment.CenterHorizontally),
                textAlign = TextAlign.Center
            )
        }
    }
}
728x90

'IT > Android' 카테고리의 다른 글

Jetpack Compose - WorkManager  (0) 2024.04.03
Jetpack Compose - Room, DataStore Practice  (0) 2024.03.29
Jetpack Compose - Room Practice  (0) 2024.03.19
Jetpack Compose - Room  (0) 2024.03.19
Jetpack Compose - APIs Practice  (0) 2024.03.12