App은 SharedPreferences를 이용하여 Integer, String과 같은 간단한 데이터를 저장할 수 있습니다. 숫자 몇개, 문자열 몇개 정도의 데이터를 저장해야 하는데 SQLite 같은 DB를 이용하기엔 번거로울 때 사용하면 좋습니다.
SharedPreferences는 App의 개별 데이터 저장소에 xml파일을 만들고, 그 파일에 Integer, String 등의 데이터를 저장하거나 읽습니다.
데이터를 저장할 때는 key/value
형태로 저장합니다.
특징을 정리하면 다음과 같습니다.
- SharedPreferences는 간단한 데이터를 앱의 개별 저장소에 xml파일로 저장
- SharedPreferences 객체를 생성할 때 파일 이름을 인자로 전달하며, 그 이름으로 xml파일이 생성됨
- 데이터를 저장할 때는
key/value
형태로 저장 - 데이터는 App의 개별 데이터 저장소에 저장되기 때문에 다른 App과 공유할 수 없음
- SharedPreferences는 put/get 메소드를 제공하여 데이터를 저장하거나 읽을 수 있음
여기서는 App이 SharedPreferences를 이용하여 데이터를 저장하고 읽는 방법에 대해서 알아보겠습니다.
SharedPreferences 객체 생성
다음과 같이 getSharedPreferences()
를 호출하여 SharedPreferences 객체를 생성할 수 있습니다.
companion object {
const val sharedPrefFile = "app_preferences"
}
private lateinit var mPreferences: SharedPreferences
override fun onCreate(savedInstanceState: Bundle?) {
....
mPreferences = getSharedPreferences(sharedPrefFile, MODE_PRIVATE);
}
SharedPreferences는 내부적으로 앱의 데이터 폴더에 xml파일을 생성한다고 했습니다.
getSharedPreferences()
의 인자에서 sharedPrefFile
는 파일의 이름입니다.
이 파일에 데이터를 저장하고, 이 파일에서 데이터를 읽어오게 됩니다.
정말로 파일이 생성되는지 확인
adb shell에서 내 앱의 데이터 폴더를 보면 ../shared_prefs/
경로에 app_preferences.xml
라는 이름으로 파일이 생성된 것을 볼 수 있습니다.
일반 디바이스는 shell이 앱의 데이터 폴더에 접근할 수 있는 권한이 없습니다. 에뮬레이터에서 adb root
로 루팅하면 데이터 폴더에 대한 접근 권한을 얻을 수 있습니다.
/data/data/com.codechacha.sharedpreferences/shared_prefs # ls
app_preferences.xml
SharedPreferences으로 데이터 저장
데이터를 저장할 때는 SharedPreferences.Editor
를 통해서 할 수 있습니다.
다음과 같이 mPreferences.edit()
으로 Editor 객체를 가져올 수 있습니다.
val preferencesEditor: SharedPreferences.Editor = mPreferences.edit()
그리고 putString()
, putInt()
등의 API를 통해 데이터를 저장할 수 있습니다.
데이터는 key/value
형태로 저장할 수 있습니다. 첫번째 인자가 key이고, 두번째 인자가 value입니다.
companion object {
const val KEY_IMAGE_HEIGHT = "image_height"
const val KEY_IMAGE_WIDTH = "image_height"
const val KEY_IMAGE_TITLE = "image_title"
const val KEY_IMAGE_WEIGHT = "image_weight"
}
preferencesEditor.putString(KEY_IMAGE_TITLE, "My photo")
preferencesEditor.putInt(KEY_IMAGE_HEIGHT, 100)
preferencesEditor.putInt(KEY_IMAGE_WIDTH, 200)
preferencesEditor.putFloat(KEY_IMAGE_WEIGHT, 2.0f)
Editor는 다음과 같은 put api를 제공하고 있습니다.
- putString()
- putInt()
- putLong()
- putBoolean()
- putStringSet()
- putFloat()
put()
을 했다고 데이터가 바로 xml파일에 저장된 것은 아닙니다.
데이터를 파일에 저장하려면 다음과 같이 apply()
를 호출해야 합니다.
apply()
는 비동기적으로(asynchronously) 동작하기 때문에 처리 중인 Thread가 Blocking되지 않습니다.
preferencesEditor.apply()
Editor.commit()
은 동기적으로(synchronously) 동작하기 때문에 처리 중인 쓰레드가 blocking 될 수 있습니다. 그렇기 때문에 저장될 때까지 기다릴 필요가 없다면apply()
를 사용하는 것이 좋습니다.
데이터가 xml에 저장되는지 확인
apply()
를 호출했을 때, xml파일에 데이터가 저장되는지 확인해보았습니다.
.../shared_prefs # cat app_preferences.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<int name="image_height" value="100" />
<int name="image_width" value="200" />
<string name="image_title">my image</string>
<float name="image_weight" value="2.0" />
</map>
데이터를 저장하고 읽는 시점
데이터를 저장하시는 이유는 보통 Activity가 재실행될 때 이전에 저장한 상태를 되돌리기 위해서입니다.
그렇기 때문에 onPause()
가 호출될 때 데이터를 저장하는 것이 좋습니다.
또는 자신이 적당하다고 생각되는 시점에 데이터를 저장하면 됩니다.
데이터를 읽을 때는 onCreate()
처럼 초기화를 하는 시점에 읽거나, 저장한 데이터가 필요한 시점에 읽어서 사용하시면 됩니다.
SharedPreferences에서 데이터 읽기
SharedPreferences에서 데이터를 읽어올 때는 Edit
객체가 필요없습니다.
다음과 같이 SharedPreferences에서 get()
api를 제공합니다.
val title = mPreferences.getString(KEY_IMAGE_TITLE, "default_title")
val width = mPreferences.getInt(KEY_IMAGE_WIDTH, 0)
val height = mPreferences.getInt(KEY_IMAGE_HEIGHT, 0)
val weight = mPreferences.getFloat(KEY_IMAGE_WEIGHT, 0.0f)
Log.d(TAG, " title: $title, width: $width, height: $height, weight: $weight")
다음과 같이 get 메소드를 제공합니다. 두번째 인자는 기본 값으로, key에 대한 데이터가 없을 때 이 값이 리턴됩니다.
- String getString(String key, String defValue)
- int getInt(String key, int defValue)
- long getLong(String key, long defValue)
- float getFloat(String key, float defValue)
- boolean getBoolean(String key, boolean defValue)
- Set
getStringSet(String key, Set defValues)
Output:
06-21 13:35:56.793 6655 6655 D MainActivity: title: my image, width: 100, height: 100, weight: 2.0
모든 데이터 삭제
어떤 파일에 저장된 모든 데이터를 삭제할 때는 Editor.clear()
를 호출하고, apply()
로 삭제된 내용이 파일에 저장되도록 하면 됩니다.
val preferencesEditor: SharedPreferences.Editor = mPreferences.edit()
preferencesEditor.clear()
preferencesEditor.apply()
실제 xml파일을 확인해보면 모두 지워진 것을 볼 수 있습니다.
../shared_prefs # cat app_preferences.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map />
Set 객체 저장 및 읽기
SharedPreferences는 Set 객체를 저장할 수 있는 API를 제공합니다. List는 데이터의 순서를 보장하고 Set는 순서를 보장하지 않기 때문에 이 둘은 다르지만, 여러 객체를 갖고 있는 Collection입니다.
갖고 있는 리스트의 저장 순서가 중요하지 않다면 Set로 저장하는 것을 고려해볼만 합니다.
다음과 같이 Set를 SharedPreferences에 저장할 수 있습니다.
companion object {
const val KEY_SETS = "key_array"
}
val preferencesEditor: SharedPreferences.Editor = mPreferences.edit()
val sets: Set<String> = setOf("Apple", "Kiwi", "Banana", "Peach")
preferencesEditor.putStringSet(KEY_SETS, sets)
preferencesEditor.apply()
xml 데이터를 확인해보면 이런식으로 저장이 되어있습니다.
../shared_prefs # cat app_preferences.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<set name="key_array">
<string>Apple</string>
<string>Kiwi</string>
<string>Peach</string>
<string>Banana</string>
</set>
</map>
읽을 때는 다음과 같이 읽으면 됩니다.
val sets = mPreferences.getStringSet(KEY_SETS, setOf())
참고
Related Posts
- Android 14 - 사진/동영상 파일, 일부 접근 권한 소개
- Android - adb push, pull로 파일 복사, 다운로드
- Android 14 - 암시적 인텐트 변경사항 및 문제 해결
- Jetpack Compose - Row와 Column
- Android 13, AOSP 오픈소스 다운로드 및 빌드
- Android 13 - 세분화된 미디어 파일 권한
- Android 13에서 Notification 권한 요청, 알림 띄우기
- Android 13에서 'Access blocked: ComponentInfo' 에러 해결
- 에러 해결: android gradle plugin requires java 11 to run. you are currently using java 1.8.
- 안드로이드 - 코루틴과 Retrofit으로 비동기 통신 예제
- 안드로이드 - 코루틴으로 URL 이미지 불러오기
- Android - 진동, Vibrator, VibrationEffect 예제
- Some problems were found with the configuration of task 에러 수정
- Query method parameters should either be a type that can be converted into a database column or a List
- 우분투에서 Android 12 오픈소스 다운로드 및 빌드
- Android - ViewModel을 생성하는 방법
- Android - Transformations.map(), switchMap() 차이점
- Android - Transformations.distinctUntilChanged() 소개
- Android - TabLayout 구현 방법 (+ ViewPager2)
- Android - 휴대폰 전화번호 가져오는 방법
- Android 12 - Splash Screens 알아보기
- Android 12 - Incremental Install (Play as you Download) 소개
- Android - adb 명령어로 bugreport 로그 파일 추출
- Android - adb 명령어로 App 데이터 삭제
- Android - adb 명령어로 앱 비활성화, 활성화
- Android - adb 명령어로 특정 패키지의 PID 찾기
- Android - adb 명령어로 퍼미션 Grant 또는 Revoke
- Android - adb 명령어로 apk 설치, 삭제
- Android - adb 명령어로 특정 패키지의 프로세스 종료
- Android - adb 명령어로 screen capture 저장
- Android - adb 명령어로 System 앱 삭제, 설치
- Android - adb 명령어로 settings value 확인, 변경
- Android 12 - IntentFilter의 exported 명시적 선언
- Android - adb 명령어로 공장초기화(Factory reset)
- Android - adb logcat 명령어로 로그 출력