Concepts of Persistence
1. 데이터 저장
- 일반적으로 데이터는 안드로이드 애플리케이션과 서버 애플리케이션이 네트워크 통신을 하며 데이터를 주고 받으며 서버 사이드 DB에 저장을 함
- 이 포스트에서는 서버 사이드에 데이터를 저장하는 것이 아닌 애플리케이션 자체에서(로컬에서) 애플리케이션이 종료되어도 사라지지 않고 영속적으로 저장하는 데이터를 다룰 것
- File Read/Write : 이미지 데이터
- Sharedpreference : 이미지 외 데이터
- Database : 이미지 외 데이터
2. File
- 자바 API로 File Read/Write
- File : 파일 및 디렉토리를 지칭하는 클래스
- FileInputStream / FileOutputStream : 파일에서 바이트 스트림(이미지)으로 데이터를 읽거나 쓰는 클래스
- FileReader / FileWriter : 파일에서 문자열 스트림으로 데이터를 읽거나 쓰는 클래스
- 파일이 저장되는 곳을 내장 메모리 공간과 외장 메모리 공간으로 구분
- 내장 메모리 공간 : 앱만 이용할 수 있는 저장 공간
- 외장 메모리 공간 : 여러 앱에서 같이 이용할 수 있는 저장 공간
- 외장 메모리 공간은 앱별 저장 공간과 공용 저장 공간으로 구분
- 앱별 저장 공간 : 특정 앱만을 위한 저장 공간
- 공용 저장 공간 : 여러 앱이 공유할 수 있는 저장 공간
val file = File(filesDir, "test.txt")
val writeStream: OutputStreamWriter = file.writer()
writeStream.write("hello world")
writeStream.flush
- 내장 메모리 공간이란 앱이 설치되면 시스템에서 자동으로 할당하는 메모리 공간
- 앱의 패키지명(식별자)으로 폴더를 만들어 주며 이 폴더가 이 앱의 내장 메모리 공간
SharedPreferences
1. SharedPreferences
- 데이터를 key-values 형태로 저장(Map 객체)
- 내부적으로 내장 메모리의 앱 폴더에 XML 파일로 데이터가 저장
2. Preferences를 얻는 방법
1) Activity.getPreferences(int mode)
- 하나의 액티비티를 위한 데이터 저장을 목적
- 이 함수를 이용한 액티비티 클래스명으로 XML 파일명이 만들어 짐(매개변수로 파일명을 따로 주지 않아도 됨)
2) Context.getSharedPreferences(String name, int mode) - common
- 앱 전체의 데이터를 key-values 형태로 저장
val sharedPref = getSharedPreferences("my-prefs", Context.MODE_PRIVATE)
3. SharedPreferences 사용 방법
1) 데이터 저장
- SharedPreferences.Editor 객체를 SharedPreferences의 edit() 함수로 획득
- 데이터를 저장하기 위해서는 SharedPreferences.Editor 클래스의 put()함수를 이용
- putBoolean(String key, boolean value)
- putInt(String key, int value)
- putFloat(String key, float value)
- putLong(String key, long value)
- putString(String key, String value)
- commit() 하는 순간 저장
2) 데이터 획득
- 데이터를 획득하기 위해서는 SharedPreferences의 getter함수를 이용
- getBoolean(String key, boolean defValue)
- getInt(String key, int defValue)
- getFloat(String key, float defValue)
- getLong(String key, long defValue)
- getString(String key, String defValue)
Settings XML
1. Settings XML
- 앱의 환경설정을 위해서는 Activity에서 event가 발생했을 때 어떤 정보를 영속적으로 저장하면 됨
- settings xml은 이런 앱의 환경설정 자동화를 목적으로 함
1. Settings XML 사용 방법
1) API 버전에 따른 라이브러리 설정
- API Level 29 이전 버전에서는 PreferenceFragment을 이용
- API Level 29 버전부터는 AndroidX Preference를 이용할 것을 권장
implementation 'androidx.preference:preference-ktx:1.1.1'
2) res/xml 폴더에 설정과 관련된 xml 파일 작성(settings.xml)
- 루트 태그가 <PreferenceScreen>
- 태그를 이용해 각각의 설정 항목 준비
- key 속성의 값과 설정 값으로 Preference에 key-values 형태로 저장
- title 속성은 화면에 출력되는 문자
- 태그 종류
- PreferenceScreen : 설정 화면 단위, 중첩 가능하며 중첩된 내용은 별도의 홤녀에 나옴
- PreferenceCategory : 설정 여러 개를 시각적으로 묶어서 표현
- CheckboxPreference : 체크박스가 나오는 설정
- EditTextPreference : 글 입력을 위한 설정
- ListPreference : 항목 Dialog을 위한 설정
- MultiSelectListPreference : 항목 Dialog인데 체크박스가 자동 추가되어 여러 선택 가능
- RingtonPreference : Rington 선택을 위한 설정
- SwitchPreference : Switch를 이용한 설정
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<SwitchPreferenceCompat
app:key="notification"
app:title="Enable message notifications"/>
</PreferenceScreen>
3) xml 적용, PreferenceFragmentCompat을 상속받은 Fragment로 설정
- 이 과정까지만 해주면 UI가 뜨고, 유저의 event를 받아 데이터를 저장하는 것까지 자동화 된다.
class SettingsFragment: PreferenceFragmentCompat() {
override fun onCreatePreference(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.settings.rootKey)
}
}
PreferenceFragmentCompat
1. PreferenceFragmentCompat
- settings.xml에서 자동으로 해주는 것 외에 필요에 따라 제어하고 싶은 경우에 사용
1) 설정을 위해 사용한 태그에 해당되는 객체를 findPreference() 태그로 획득
<EditTextPreference
android:key="id"
android:title="ID 설정"
android:isPreferenceVisible="false" />
val idPreference: EditTextPreference? = findPreference("id")
idPreference?.isVisible = true
2) 나 에 값 입력시 summary 값 변경
- SimpleSummaryProvider 이용 : 유저가 입력한 값을 summary에 출력
soundPreference!!.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance())
- SummaryProvider 하위 클래스 : 유저가 입력한 값이 아닌 개발자가 원하는 값을 출력하고 싶은 경우
idPreference?.summaryProvider =
Preference.SummaryProvider<EditTextPreference> { preference ->
val text = preference.text
if(TextUtils.isEmpty(text)) {
"설정이 되지 않았습니다."
} else {
"설정된 ID 값은 $text 입니다."
}
}
3) 유저가 설정을 하기 위해서 화면을 터치하는 순간의 이벤트 처리
- setOnPreferenceClickListener()을 이용해 이벤트 핸들러를 지정
idPreference?.setOnPreferenceClickListener {
true
}
4) 유저가 설정 값을 변경한 순간의 이벤트 처리
- Preference.OnPreferenceChangeListener을 이용 : 각 Preference 객체에 적용
- SharedPreferences.OnSharedPreferenceChangeListener 이용 : 모든 설정 객체의 변경을 하나의 이벤트 핸들러에서 감지
idPreference?.setOnPreferenceChangeListener { preference, newValue ->
Log.d("preference", "preference key : ${preference.key}, newValue : $newValue")
true
}