본문 바로가기
Mobile App

[안드로이드] - Android Preferences data storage

by Jman 2022. 7. 21.

안드로이드 시스템에서 제공되는 앱 데이터 저장 종류 중에, 앱 환경설정 데이터 저장소에 대해서 알아보자.

 

환경설정 라이브러리에서 저장한 Preference 값을 저장하고 사용하는 방법을 설명하겠다.

환경설정 데이터 저장소

데이터 유지하는 방법

  • SharedPreferences : 기본적으로 Preference 는 SharedPreferences 를 사용하여 값을 저장한다. SharedPreferences API 를 사용하면 애플리케이션 세션에 걸쳐 저장된 파일에서 간단하기 Key-Value 쌍을 읽고 쓸 수 있다. 환경설정 라이브러리는 비공개 SharedPreferences 인스턴스를 사용하므로 애플리케이션만 인스턴스에 엑세스할 수 있다.
  • PreferenceDataStore : 환경설정 라이브러리는 기본적으로 SharedPreferences 를 사용하여 데이터를 유지하지만, SharedPreferences 가 항상 이상적인 해결방법은 아니다. 예를 들어 애플리케이션에 사용자 로그인이 필요하다면, 설정이 다른 기기 및 플랫폼에 반영되도록 클라우드에 애플리케이션 설정을 유지하고 싶을 수도 있다. 마찬가지로 애플리케이션에 기기 별 구성 옵션이 있다면 기기의 각 사용자가 별도의 설정을 가지게 된다. 그럴 경우 SharedPreferences 는 이상적인 해결방법이 아니다.

 

환경설정 값 읽어오기

사용 중인 SharedPreferences 객체를 가져오려면, PreferenceManage.getDefaultSharedPreferences()를 호출한다 이 메서드는 애플리케이션의 모든 위치에서 작동한다.

<EditTextPreference
        app:key="signature"
        app:title="Your signature"/>

 

val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this /* Activity context */)
val name = sharedPreferences.getString("signature", "")

 

환경설정 값의 변경사항 수신대기

Preference 값의 변경사항을 수신 대기하려면 다음 두 개의 인터페이스 중에서 선택하면 된다.

  • Preference.OnPreferenceChangeListener
  • SharedPreferences.OnSharedPreferenceChangeListener

 

OnPreferenceChangeListener

Preference 의 값이 변경되려고 하는 때를 수신 대기할 수 있다. 여기에서 변경이 필요한지 검증할 수 있다.

override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean {
    Log.e("preference", "Pending Preference value is: $newValue")
    return true
}

다음으로 이 리스너를 다음과 같이 setOnPreferenceChangeListener() 를 사용하여 직접 설정해야 한다.

preference.onPreferenceChangeListener = ...

OnSharedPreferenceChangeListener

SharedPreferences 를 사용하여 Preference 값을 유지한다면SharedPreferences.OnSharedPreferenceChangeListener를 사용하여 변경사항을 수신 대기할 수도 있다.

이렇게 하면, Preference 에 저장된 값이 변경될 때(ex 서버와 설정을 동기화) 를 수신 대기할 수 있다.

override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
    if (key == "signature") {
        Log.i(TAG, "Preference value was updated to: " + sharedPreferences.getString(key, ""))
    }
}

또한 아래와 같이 registerOnSharedPreferenceChangeListener() 를 통해 리스너를 등록해야 한다.

preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(...)

 

Activity 또는 Fragment 에서 수명 주기를 올바르게 관리하기 위해 onResume()onPause() 콜백에서 이 리스너를 등록 및 등록 취소를 해주어야 한다.

override fun onResume() {
    super.onResume()
    preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
}

override fun onPause() {
    super.onPause()
    preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
}

 

맞춤 데이터 저장소 사용

SharedPrefernces 를 사용하여 Preference객체를 유지하는 것이 좋기는 하지만, 맞춤 데이터 저장소를 사용할 수도 있다.

예를 들어, 맞춤 데이터 저장소는 애플리케이션이 값을 데이터베이스에 유지하거나 값이 기기 별로 저장될 때 유용하다.

 

데이터 저장소 구현

맞춤 데이터 저장소를 구현하려면, 먼저 PreferenceDataStore를 확장한 클래스를 만든다. 

// String 값을 처리하는 데이터 저장소

class DataStore : PreferenceDataStore() {
    override fun putString(key: String, value: String?) {
        // Save the value somewhere
    }

    override fun getString(key: String, defValue: String?): String? {
        // Retrieve the value
    }
}

사용자 인터페이스를 차단하지 않으려면, 기본 스레드가 아닌 곳에서 시간 소모가 많은 작업을 실행해야 한다.

값을 유지하는 동안 데이터 저장소를 포함하는 Fragment 또는 Activity 가 제거될 수 있기 때문에 사용자가 변경한 값을 잃어버리지 않도록 데이터를 직렬화해야 한다.

 

데이터 저장소 사용 설정

데이터 저장소를 구현 한 뒤에 Preference 객체가 기본 SharedPreferences 를 사용하는 대신 데이터 저장소를 사용하여 값을 유지하도록 onCreatePreferences() 에 새 데이터 저장소를 설정해야 한다.

데이터 저장소는 각 Preference 또는 전체 계층 구조에서 사용 설정될 수 있다.

 

특정 Preference 용 맞춤 데이터 저장소를 사용 설정하려면 아래와 같이 PreferencesetPreferenceDataStore() 를 호출해야 한다.

val preference: Preference? = findPreference("key")
preference?.preferenceDataStore = dataStore

 

만약 전체 계층 구조용 맞춤 데이터 저장소를 사용 설정하려면? PreferenceManage 의 setPrefereenceDataStore() 를 호출한다.

val preferenceManager = preferenceManager
preferenceManager.preferenceDataStore = dataStore

특정 Preference용으로 설정된 데이터 저장소는 대응하는 계층 구조용으로 설정된 모든 데이터 저장소를 재정의 한다.

대부분의 경우 전체 계층 구조용 데이터 저장소를 설정해야 한다.