[17. 저장소에 데이터 보관]
<앱 데이터 보관 방법> (1) 외부 서버에 저장 -> 통신으로 주고받기 (2) 내부 저장소에 저장 : 3가지 제공 - 데이터베이스에 보관 - 파일에 보관 - 공유된 프리퍼런스에 보관 |
[17-1. 데이터베이스에 보관]
[안드로이드의 DBMS] | SQLite
-SQLite : 오픈소스로 만들어진 데이터베이스 관리 시스템
-테이블의 데이터를 앱 저장소에 파일로 저장.
-외부 앱에서 접근 불가
-실제 데이터를 SQLite 가 관리해줌
[질의문 작성]
-SQLite 사용하려면 SQLiteDatabase API 이용해야 함
▶[질의문을 실행해주는 함수 사용]
(1) SQLiteDatabase 객체 생성 (= 데이터베이스 객체)
- openOrCreateDatabase() 함수 호출하여 객체 받기
val db = openOrCreateDatabase(“DB파일명”, Context.MODE_PRIVATE, null)
(2) 이 객체에 정의된 질의문 실행 함수 사용
execSQL(질의문, 데이터배열) | create/alter/drop/insert/update/delete문 실행 함수 |
rawQuery(질의문, 데이터배열) | select문 실행 (테이블 데이터 조회) |
⇒ rawQuery() 함수 반환 객체 = Cursor 객체
1) Cursor 객체로 행 선택 : moveTo~ 함수 이용
moveToFirst() | 첫 번째 행 선택 |
moveToLast() | 마지막 행 선택 |
moveToNext() | 다음 행 선택 |
meveToPosition() | 매개변수로 지정한 위치의 행 선택 |
moveToPrevious() | 이전 행 선택 |
2) Cursor 객체로 선택한 행의 -> 열 데이터 가져오기
-타입에 따라 선택. 매개변수에 가져올 데이터 저장된 열 인덱스 지정
getString(int 열 인덱스) |
getInt(int 열 인덱스) |
getDouble(int 열 인덱스) |
▶[질의 함수 사용]
-insert() / update() /delete()/ query() 함수에 질의문의 각 항목별 정보를 매개변수로 대입
-> 질의문으로 만들어 실행됨
1) insert(), update() 의 ContentValues 객체 : 열 데이터 집합
-이 객체에 ‘키-값’ 형태로 데이터 집합 저장 (키에 열 테이블이름, 값에 데이터)
public long insert (String table, String nullColumnHack, ContentValues values) |
public int update (String table, ContentValues values, String whereClause, String[] wereArgs) |
val values = ContentValues()
values.put(“name”, “kkang”)
values.put(“phone”, “010112”)
db.insert(“USER_TB”, null, values)
2) query() 함수의 매개변수 정보
-각 매개변수로 질의문 만들어 실행해줌
table | 조회할 테이블명 |
columns | 가져올 값의 열 이름 배열로 지정 |
selection | select문의 where 조건절 문자열 |
sesctionArgs | 질의문 속 ?에 대응하는 데이터 배열 |
groupBy | select문의 group by절 문자열 |
having | select문의 having 조건 |
orderBy | select문의 order by 조건 |
[데이터베이스 관리] : SQLiteOpenHelper 클래스 이용
-SQLiteOpenHelper 클래스 : DB 관리 코드 추상화 클래스
-테이블 생성/변경/제거 코드의 추상화
-이 클래스 상속받는 하위 클래스 작성해서 DB 관리 O
구조적 분리 작성 O -( 테이블 생성 코드/테이블 변경 코드) 분리 작성 O -( 데이터 조작 질의문 ) 따로 작성 |
<SQLiteOpenHelper의 하위 클래스 >
class DBHelper(context: Context) : SQLiteOpenHelper(context, “testdb”, null, 1) {
override fun onCreate(db: SQLiteDatabase?){ }
override fun onUpgrade(db: SQLiteDatabase?, oldVersion:Int, newVersion: Int){ }
onCreate() | 앱 설치 후 최초 한 번만 호출됨 이 곳에 데이터베이스 테이블 생성 코드 주로 작성 |
onUpgrate() | DB 버전 정보 바뀔 때마다 반복 호출됨 이 곳에 테이블 스키마 변경 코드 주로 작성 |
<SQLiteOpenHelper 이용 시, SQLiteDatabase 객체 생성 O>
-SQLiteOpenHelper클래스의 readableDatabase/writeableDatabase 속성으로 객체 생성O
[17-2. 파일에 보관]
-파일 : 앱에서 직접 파일을 만들고 코드에서 직접 데이터 읽고 씀
-데이터페이스/프리퍼런스 : 내부적으로 파일 저장되지만 코드에서 직접 X. 특정 API 이용
[안드로이드 앱 파일 다루기]
-java.io 패키지 제공 클래스 이용
File | 파일. 디렉터리 지칭 클래스 |
FileInputStream /FileOutputStream | 바이트 스트림으로 데이터 읽고 쓰는 클래스 |
FileReader / FileWriter | 문자열 스트림으로 데이터 일고 쓰는 클래스 |
[안드로이드 파일 저장소 구분]
▶[내장 메모리의 파일 이용]
-내장 메모리 : 앱 설치되면 시스템에서 자동 할당하는 공간
-다른 앱에서는 접근 X. 주로 민감한 데이터를 내장 메모리에 저장
방법 ① java.io의 File 클래스 이용
- File() 생성자에 전달 (Context 객체의 filesDir 속성 지정/ 파일명)
<파일 객체 생성 후 '데이터 쓰기'>
val file = File(filesDir, “test.txt”) //파일 객체 생성
val writeStream: OutputStreamWriter = file.writer() //파일 Writer 생성
writeStream.write(“hello world”) //데이터 쓰기
writeStream.flush()
<파일에 저장한 '데이터 읽기'>
val readStream : BufferedReader = file.reader().buffered() //파일 Reader 생성
readStream.forEachLine {
Log.d(“kkang”, “$it”)
}
방법 ② Context 객체 제공 openFileOuput(), openFileInput() 함수 이용
openFileOutput(“test.txt”, Context.MODE_PRIVATE).use{
it.write(“hello world” .toByteArray() ) //쓰기
}
openFileInput(“test.txt”).bufferedReader().forEachLine {
Log.d(“kkand”, “$it”) //읽기
}
▶[외장 메모리의 파일 이용]
<기본 준비>
(1) 외장 메모리 사용 가능 여부 판단
Environment.getExternalStorageState() 함수 반환값 == MEDIA_MOUNTED 이면 사용 가능 상태 O
(2) 매니페스트 설정
-버전과 파일 이용 방식에 따라 다르지만 API 호환성 위해 모두 설정 필요
[->매니 페스트 속 퍼미션 설정]
android.permission.READ_EXTERNAL_STORAGE |
android.permission.WRITE_EXTERNAL_STORAGE |
[->매니 페스트 속 requestLegacyExternalStorage 값 설정]
⇒[ 中. 앱별 저장소 이용]
*앱별 저장소 : 개별 앱에 할당된 공간. 기본적으로 해당 앱에서만 접근 O
-앱이 삭제되면 앱별 저장소 파일도 모두 삭제됨
-만약, 외부 앱에서 접근 가능하게 하려면 ‘파일 프로바이더’로 공개
<앱별 저장소 위치 구하기> : getExternalFilesDir() 함수
-함수의 매개변수에 파일 종류 나타냄 (Environment 상수값)
Environment.DIRECTORY_PICTURES |
Environment.DIRECTORY_DOCUMENTS |
Environment.DIRECTORY_MUSIC |
Environment.DIRECTORY_MOVIES |
<이 함수 null일 때 반환하는 기본 위치>
/storage/emulated/0/Android/data/패키지명/files |
<파일 프로바이더로 외부 공유>
1) 파일 프로바이더 XML 파일 - res/xml 디렉터리 하위에 만듬 - 외부에 공유할 파일 경로 : external-path의 path 속성에 지정 2) 매니페스트에 <provider> 태그로 XML 파일 등록 -<provider> 의 하위 <meta-data>태그의 resource 속성에 파일 명시 |
⇒[ 中. 공용 저장소 이용]
*공용 저장소 : 모든 앱을 위한 공간
-앱을 삭제해도 파일 삭제 X
-안드로이드 시스템에서 해당 파일 종류에 따라 지정한 폴더임
-공용 저장소는 시스템이 제공하는 API 이용하여 접근
<공용 저장소에 저장된 파일 정보 가져와서 로그로 출력>
contentResolver.query() 함수의 첫 번째 매개변수에 지정 가능 Uri 값
MediaStore.Images | 공용 저장소 DCIM. Pictures 디렉터리 가리킴 |
MediaStore.Video | DCIM. Movies, Pictures 디렉터리 가리킴 |
MediaStore.Audio | Alarms, Audiobooks, Music, Notifications, Podcasts, Ringtones 디렉터리 가리킴 |
<읽어온 파일 정보 이용 -> 데이터 Uri 값 가져오기>
ContentUris.withAppendedId() 함수의 두 번째 매개변수가 가져온 이미지 식별값
반환된 Uri값으로 이미지 읽을 수 있는 InputStream 객체 얻어옴
[17-3. 공유된 프리퍼런스에 보관]
[공유된 프리퍼런스 이용]
-공유된 프리퍼런스 : 플랫폼 API에서 제공하는 클래스. 데이터를 키-값 형태로 저장
-간단한 데이터 저장에 유용. 데이터를 내장 메모리 앱 폴더의 XML 파일로 저장
<SharedPrefernce 객체 얻는 방법>
1) '액티비티 단위'로 데이터 저장 방법 Activity.getPreferences(int mode) -이 함수 호출한 액티비티 클래스명 XML 파일 자동 생성되고 이곳에 데이터 저장됨 2) '앱 전체' 데이터 키-값 형태 저장 방법 Context.getSharedPreferences(String name, int mode) -이 함수 첫 번째 매개변수에 지정한 문자열 파일에 데이터 저장됨 |
<공유된 프리퍼런스 이용 ‘데이터 저장>
(1) SharedPreferences의 edit() 함수로 ‘SharedPreferences.Editor 객체 얻기
(2) 얻은 객체의 put_함수 이용해서 데이터 담기
putBoolean (String key, boolean value) |
putInt (String key, int value) |
putFloat (String key, float value) |
putString (String key, String value) |
(3) commit() 호출하는 순간 데이터 저장됨
<공유된 프리퍼런스 이용 ’데이터 가져오기>
-SharedPreferences의 getter() 함수 이용
getBoolean (String key, boolean defValue) |
getFloat (String key, float defValue) |
getInt (String key, int defValue) |
getLong (String key, long defValue) |
getString (String key, String defValue) |
[앱 설정 화면 만들기]
-AndroidX의 Preference 이용 권장 : 앱 설정 기능 제공 제트팩의 API
≫ <preference 이용 방법>
(1) build.gradle 파일에 라이브러리 dependencies 추가
implementation ‘androidx.preference:preference-ktx:1.1.1’ |
(2) 설정 XML 파일 만들기
-루트 태그 <PreferenceScreen>
-태그 하위에 <SwitchPreferenceCompat>, <Preference> 로 설정 항목 준비
(3) 이 XML 파일을 코드에 적용
-PreferenceFragmentCompat 클래스 상속받은 프래그먼트로 설정 화면 준비
-상위 클래스의 onCreatePreferences() 함수 재정의하면서 내부에
setPreferencesFromResource() 로 위 설정 XML 파일 전달
(4) 이 프래그먼트를 액티비티에 출력
≫ <설정 화면 구성> | 설정 항목 너무 多 경우
1) 한 화면 안에, 관련 있는 항목끼리 묶어 화면 구성
: <PreferenceCategory> 태그 사용
- 한 화면에 보이는 항목끼리 구분 지어 출력 O
2) 항목들을 설정 화면 여러 개에 나누어 화면 구성
: <Preference> 태그 사용
① 코드에서 분할 화면 구성
<설정 화면 분할>
1) 분리한 설정 화면 개수만큼, 설정 XML과 프래그먼트를 각각 만들기 2) 분리한 설정화면들을 모두 포함시켜 보여줄 ‘메인 설정 XML’ 작성 3) 메인 설정 XML에서 각 설정 화면을 <Preference> 태그로 지정 4) <Preference> 태그의 fragment 속성에 항목 클릭 시 전환될 설정화면 지정 |
<액티비티에서 분할된 설정화면 보이기>
1) PreferenceFragmentCompat.OnPreferenceStartFragmentCallback 인터페이스 구현 액티비티 2) 내부에 onPreferenceStartFragment() 함수 재정의하여 작성 //이 함수는 설정 화면 바뀔 때마다 자동 호출 함수 //따라서 이 함수 안에 설정 화면 바뀔 때마다 액션바에 출력될 제목 지정도 가능 |
② ‘인텐트’ 이용. 오직 XML 설정만으로 구현
- 메인 설정 화면에서 ‘인텐트’를 이용해 하위 설정 화면을 띄우는 방식 ) - 메인 설정 화면에서 <Preference> 태그 하위에 <intent> 태그로 바뀔 설정 화면 지정 (+) 이때 <intent> 태그 하위에 <extra> 태그로 엑스트라 데이터 포함시킬 수 O (+) 명시적 or 암시적 인텐트 정보 설정도 가능 |
≫ <코드에서 설정 제어>
- 코드에서 설정 화면 속 설정값을 제어하는 방법
1) 각 설정 항목 객체를 findPreference() 함수로 얻기 //findPreference() 의 매개변수는 XML에서 작성한 각 설정 태그 key 속성값임 2) findPreference()로 얻은 각 설정 항목 객체로 접근하여 각 설정값을 상황에 맞게 코드에서 조정 가능 (ex. 코드 안에서 isVisible / title / summary 등의 값을 변경 O ) |
≫ <코드에서 일부 자동 설정>
- <EditTextPreference> or <ListPreference> 의 경우 사용자 입력값 / 선택값을 summary에 자동 지정하려면 SimpleSummaryProvider 이용 - 이 객체 이용하면 사용자 설정값이 그대로 문자열로 출력됨 - 이 객체의 하위 클래스에서 이벤트 처리도 가능 |
≫ <설정한 값 가져오기>
-프리퍼런스 이용하면 설정 내용이 XML 파일로 자동 저장됨 단, 설정값은 직접 가져와야 함 PreferenceManager.getDefaultSharedPreferences() 함수 이용 |
≫ <설정 변경 순간을 감지> (2가지)
1) Preference.OnpreferenceChangeListener 이용하는 방법
각각의 프리퍼런스 객체마다 각 이벤트 핸들러 직접 지정하여 각 객체 설정 내용 변경 순간의 이벤트를 처리
2) SharedPreferences.OnSharedPreferenceChangeListener 이용하는 방법
모든 설정 객체의 변경을 ‘하나의 이벤트 핸들러’에서 처리
⇒ [단, 이 방식 이용 시 사용 조건]
1) 설정 프래그먼트 클래스에서 SharedPreferences.OnsharedPreferenceChangeListener 구현 2) onSharedPreferenceChanged() 재정의 3) registerOnSharedPreferenceChangeListener() 이용하여 이벤트 핸들러 등록 4) unregisterOnSharedPreferenceChangeListener() 이용하여 이벤트 등록 해제 |
[17-4. 개선된 할 일 목록 앱 만들기] : 실습
[참고] : Do It 안드로이드 앱 프로그래밍 with 코틀린 |
'App(앱)_관련 공부 모음 > [교재] Andorid App_Kotlin 기반' 카테고리의 다른 글
19. [위치 정보 활용] (0) | 2022.03.30 |
---|---|
18. [네트워크 프로그래밍] (0) | 2022.03.26 |
16. [콘텐츠 프로바이더 컴포넌트] (0) | 2022.03.24 |
15. [서비스 컴포넌트] (0) | 2022.03.24 |
14. [브로드캐스트 리시버 컴포넌트] (0) | 2022.03.23 |