어플리케이션을 개발하면서, SharedPreferences
를 사용하는 경우가 많았다.
특히 SharedPreference
를 사용하면서 반복적인 작업 (get/set
작성) 에 의해 코드가 매우 길어지는 경우가 발생했다.
6주간 인턴십을 하면서 해당 방법을 적용해보고는 싶었지만 수정해야할 부분이 상당히 많았기 때문에 고민만 하고 실제로 적용하지는 않았다.
인턴십이 끝나고 어느정도 여유가 생긴 지금 Delegate
를 통해 해당 문제를 개선해보고자 한다.
SharedPreferences란?
SharedPreferences
란 데이터를 key-value
쌍으로 저장하고 검색하기 위한 도구이다.
어디에 사용할까?
일반적으로 앱을 종료하고 다시 시작해도 지속되어야 하는 기본 설정 값이나 앱의 설정 값을 저장하는 데 사용된다.
SharedPreferences의 문제
SharedPreferences
를 사용하다 보면, 다음과 같은 반복적인 코드 작성이 발생하게 된다.
반복적인 상황
- 값을 저장한다.
- 값을 검색한다.
만약 초기 설정 값을 많이 사용하는 애플리케이션을 개발하게 된다면, 위와 같은 반복적인 상황에 의해 코드가 복잡해지게 된다.
다음과 같은 문제를 Delegate
하여 해결해보고자 한다.
Delegate - 위임
위임
이란 내가 가진 책임의 일부를 다른 객체에 위임하는 것이다.
주로 property
에 대한 getter
나 setter
를 제어하고자 할 때 사용이 된다.
Kotlin
에서 Delegate
를 통해 위의 반복적인 작업을 처리하는 Delegator
를 설정하여 SharedPreferences
를 관리하도록 하는 것이 이번 포스팅의 목표이다.
SharedPreferencesDelegate의 정의
위임을 위한 SharedPreferencesDelegate
클래스를 정의한다.
class SharedPreferencesDelegate<T>(
private val sharedPreferences: SharedPreferences,
private val key: String,
private val defaultValue: T) {}
속성에 대한 설명은 다음과 같다.
sharedPreferences
: SharedPreferences 인스턴스.key
: SharedPreferences에서 값에 접근하기 위한 키.defaultValue
: 값이 없을 경우 사용할 기본값.
다음은 delegate
의 getter
와 setter
는 operator
를 통해 정의한다.
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
// 프로퍼티 값을 반환하는 로직
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
// 프로퍼티 값을 설정하는 로직
}
getter
나 setter
를 위의 코드처럼 반드시 제너릭 형태로 정의할 필요는 없지만, SharedPreferences
의 경우에는 특정 데이터 타입의 고정되어 있지 않고 여러 데이터 타입을 처리할 수 있어야 한다.
SharedPreferences에 저장할 수 있는 데이터 유형
저장할 수 있는 데이터 유형은 크게 6가지가 있다.
- Boolean:
putBoolean()
및getBoolean()
메서드를 사용하여 불리언 값 저장 및 검색 가능. - Int:
putInt()
및getInt()
메서드를 사용하여 정수 값 저장 및 검색 가능. - Long:
putLong()
및getLong()
메서드를 사용하여 롱 값 저장 및 검색 가능. - Float:
putFloat()
및getFloat()
메서드를 사용하여 부동 소수점 값 저장 및 검색 가능. - String:
putString()
및getString()
메서드를 사용하여 문자열 값 저장 및 검색 가능. - Set :
putStringSet()
및getStringSet()
메서드를 사용하여 문자열 집합 저장 및 검색 가능.
다음과 같이 여러가지 타입의 처리를 하기 위해 제너릭
을 사용한다
정의
이제 6가지 타입에 맞추어 getter
와 setter
를 정의한다.
만약에 해당 타입이 정의될 수 없는 타입일 경우에는 에러를 발생시킨다.
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return with(sharedPreferences) {
val data: Any = when (defaultValue) {
is Long -> getLong(key, defaultValue)
is String -> getString(key, defaultValue) ?: ""
is Int -> getInt(key, defaultValue)
is Boolean -> getBoolean(key, defaultValue)
is Float -> getFloat(key, defaultValue)
else -> throw IllegalArgumentException("해당 타입은 저장할 수 없습니다.")
}
data as T
}
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
with(sharedPreferences.edit()) {
when (value) {
is Long -> putLong(key, value)
is String -> putString(key, value)
is Int -> putInt(key, value)
is Boolean -> putBoolean(key, value)
is Float -> putFloat(key, value)
else -> throw IllegalArgumentException("해당 타입은 저장할 수 없습니다.")
}.apply()
}
}
전체적인 코드
class SharedPreferencesDelegate<T>(
private val sharedPreferences: SharedPreferences,
private val key: String,
private val defaultValue: T) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return with(sharedPreferences) {
val data: Any = when (defaultValue) {
is Long -> getLong(key, defaultValue)
is String -> getString(key, defaultValue) ?: ""
is Int -> getInt(key, defaultValue)
is Boolean -> getBoolean(key, defaultValue)
is Float -> getFloat(key, defaultValue)
else -> throw IllegalArgumentException("해당 타입은 저장할 수 없습니다.")
}
@Suppress("UNCHECKED_CAST")
data as T
}
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
with(sharedPreferences.edit()) {
when (value) {
is Long -> putLong(key, value)
is String -> putString(key, value)
is Int -> putInt(key, value)
is Boolean -> putBoolean(key, value)
is Float -> putFloat(key, value)
else -> throw IllegalArgumentException("해당 타입은 저장할 수 없습니다.")
}.apply()
}
}
}
Delegate
확장 함수
SharedPreference
에 대한 Delegate
를 생성하기 위해 다음과 같이 작성한다.
fun <T> SharedPreferences.delegate(
key: String,
defaultValue: T
): SharedPreferencesDelegate<T> = SharedPreferencesDelegate(this, key, defaultValue)
사용하기
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
// SharedPreferencesDelegate를 사용하여 delegate 생성
val nameValue: String by sharedPreferences.delegate("name", "")
// 값에 접근
val value = nameValue
// 값을 변경
nameValue = "Shino72"
위 코드에서 SharedPreferencesDelegate
의 delegate
확장 함수를 사용하여 name
이라는 키와 기본값을 지정하여 delegate
를 생성한다.
이렇게 하면 name
키에 저장된 값이 이미 존재한다면 해당 값을 불러올 것이고, 그렇지 않다면 기본값으로 설정된 빈 문자열을 반환한다.
그리고 이 값을 변수 value
에 할당하여 사용할 수 있다.
이렇게 하면 간단하게 사용할 수 있다!
PreferenceManager deprecated
PreferenceManager deprecated
는 api 29
이후로 deprecated
되었다.
build.gradle
에 다음 코드를 추가하여 사용하거나
implementation 'androidx.preference:preference:1.2.0'
아니면,
val sharedPreferences: SharedPreferences = context.getSharedPreferences("prefs", Context.MODE_PRIVATE)
다음 방법으로 대체한다.
'안드로이드 > KOTLIN' 카테고리의 다른 글
[Kotlin] - 버전에 따라 다르게 갤러리에 사진 저장하기 (0) | 2023.09.13 |
---|---|
[Fragment] Bundle에 객체를 전달하기 (0) | 2023.03.23 |
[Parcelize] intent에 Data class를 넣어서 전달하기 (0) | 2023.03.06 |
Retrofit @Get, @Query 인코딩 문제 해결방법 (0) | 2023.02.01 |
[Jitpack] 사용하기 (0) | 2023.01.17 |