Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 반복문
- StatefulWidget
- 뷰바인딩
- 프래그먼트
- 안드로이드 스튜디오
- 람다식
- spacer
- 추상메소드
- 지연초기화
- button
- Widget
- 액티비티 생명주기
- appbar
- StatelessWidget
- If
- 변수
- margin
- setState
- Kotlin
- expanded
- Flutter
- 두 수의 나눗셈
- 상속
- 빌드 프로세스
- 패스트캠퍼스
- 인스턴스
- 프로그래머스
- padding
- 리스트뷰
- SizedBox
Archives
- Today
- Total
Y_Ding
Room 본문
Room
안드로이드에서 데이터를 저장하는 방법 3가지 중 한가지
데이터베이스는 안드로이드에서는 SQLite라는 것을 사용
SQLite를 쉽게 사용할 수 있게 만들어진 것이 Room 라이브러리
- 쉽게 Query를 사용할 수 있는 API 제공
- 컴파일 시간에 Query를 검증함
- Query 결과를 LiveData로하여 데이터베이스가 변경될 때마다 쉽게 UI를 변경 가능
- SQLite보다 Room을 사용할 것을 안드로이드에서 권장함
- Room의 주요 3요소
- @Database : 클래스를 데이터베이스로 지정하는 어노테이션, RoomDatabase를 상속받는 클래스여야함
- Room.databaseBilder를 이용하여 인스턴스 생성
- @Entity : 클래스를 테이블 스키마로 지정하는 어노테이션
- @Dao : 클래스를 DAO(Data Access Object)로 지정하는 어노테이션
- 기본적인 insert, delete, update SQL은 자동으로 만들어주고, 복잡한 SQL은 직접 만들 수 있음
- Room을 쓰려면 gradle 파일 설정을 해줘야 함
- @Database : 클래스를 데이터베이스로 지정하는 어노테이션, RoomDatabase를 상속받는 클래스여야함
plugins {
....
id 'kotlin-kapt'
}
.....
dependencies {
......
def room_version = "2.5.1"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
kapt "androidx.room:room-compiler:$room_version"
// optional - Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:$room_version"
// optional - Test helpers
testImplementation "androidx.room:room-testing:$room_version"
}
* Androidx 사용하는 경우를 가정하고, 안드로이드 스튜디오와 SDK는 최신 버전 사용
Entity 생성
- 테이블 스키마 정의
- 테이블들은 어떤 컬럼들을 정의를 하는 것이 스키마
Table을 만드는 쿼리문
CREATE TABLE student_table(student_id INTEGER PRIMARY KEY, name TEXT NOT NULL);
* student_table이라는 테이블을 생성
* 테이블 안에 student id와 name이 들어갈 것
* id는 INT로 들어가고, PRIMARY KEY(unique한 값, 중복되지 않음)을 가짐
* name에는 text가 들어가고 null값이 들어갈 수 없음
@Entity data class Student
@Entity(tableName = "student_talbe")
data class Student {
@PrimaryKey
@ColumnInfo(name = "student_id")
val id: Int,
val name: String
}
DAO 생성
- interface나 abstract class로 정의되어야 함
- 어노테이션에 SQL 쿼리를 정의하고 그 쿼리를 위한 메소드를 선언해야 함
- 가능한 어노테이션 : @Insert, @Update, @Delete, @Query
@Query("SELECT * from table") fun getAllData() : List<Data>
@Query("SELECT * from table") fun getAllData() : LiveData<Data>
* 리턴되는 데이터의 값을 LiveData<>로 하면,
나중에 데이터가 업데이트될 때 Observer를 통해 할 수 있음
@Query("SELECT * FROM student_table WHERE name = :sname")
suspend fun getStudentByName(sname: String): List<Student>
* student_table에서 모든 데이터(*)를 가져올건데 이름이 sname인것을 찾아줘라
* suspend는 kotlin coroutine을 사용한 것
* 나중에 이 메소드를 호출할 때는 runBlocking{} 내에서 호출해야 함
- @Insert, @Update, @Delete는 SQL쿼리를 작성하지 않아도 컴파일러가 자동으로 생성(Room을 쓰는 이유)
- @Insert나 @Update는 key가 중복되는 경우 처리를 위해 onConflict를 지정 가능
- OnConflicStrategy.ABORT : key 충돌시 종료
- OnConflicStrategy.IGNORE : key 충돌시 무시
- OnConflicStrategy.REPLACE : key 충돌시 새로운 데이터로 변경
- @Update나 @Delete는 primary key에 해당되는 튜플을 찾아서 변경/삭제함
Database 생성
- RoomDatabase를 상속하여 자신의 Room 클래스를 만들어야 함
- 포함되는 Entity들과 데이터베이스 버전을 @Database annotation에 지정함
- 앱을 사용하다가 추가 개발이 필요해서 테이블을 추가해야 하는 경우가 생길 때 테이블이 추가된 채로 앱을 업데이트 하게 되면 데이터베이스가 업데이트가 되지 않은 상태이기 때문에 에러가 발생함
- 그렇기 때문에 버전 관리가 필요함
- 기존에 깔려있던 앱에 Migration을 이용해 테이블을 추가 및 변경할 수 있음
- RoomDatabase 객체의 addMigration() 메소드를 통해 수행
데이터 베이스 만드는 방법
@Database(entities = [Student::class, ClassInfo::class, Enrollment::class, Teacher::class], version = 1)
abstract class MyDatabase : RoomDatabase() {
abstract fun getMyDao() : MyDAO
companion object {
private var INSTANCE: MyDatabase? = null
private val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) { 생략 }
}
private val MIGRATION_2_3 = object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) { 생략 }
}
fun getDatabase(context: Context) : MyDatabase {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(
context, MyDatabase::class.java, "school_database")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3)
.build()
}
return INSTANCE as MyDatabase
}
}
}
Migration
Room.databaseBuilder(...).addMigrations(MIGRATION_1_2, MIGRATION_2_3)
private val MIGRATION_1_2 = object : Migration(1, 2) { // version 1 -> 2
override fun migrate(database: SupportSQLiteDatabase) {
// COLUMN을 하나 추가 한다
database.execSQL("ALTER TABLE student_table ADD COLUMN last_update INTEGER")
}
}
private val MIGRATION_2_3 = object : Migration(2, 3) { // version 2 -> 3
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE class_table ADD COLUMN last_update INTEGER")
}
}
* ALTER TABLE : 테이블을 변경하는 것
UI연결
- RoomDatabase 객체에게 DAO 객체를 받아오고, 이 DAO객체의 메소드를 호출하여 데이터 베이스를 접근함
myDao = MyDatabase.getDatabase(this).getMyDao()
runBlocking { // (주의) UI를 블록할 수 있는 DAO 메소드를 UI 스레드에서 바로 호출하면 안됨
myDao.insertStudent(Student(1, "james")) // suspend 지정되어 있음
}
val allStudents = myDao.getAllStudents() // LiveData는 Observer를 통해 비동기적으로 데이터를 가져옴
UI연결-LiveData
- LiveData<> 타입으로 리턴되는 DAO 메소드
- observe() 메소드를 이용해 Observer 지정
- 데이터가 변경될 때마다 자동으로 Observer의 onChanged()가 호출됨
- LiveData<>를 리턴하는 DAO메소드는 Observer를 통해 비동기적으로 데이터를 받기 때문에, UI스레드에서 직접 호출해도 상관 없음
val allStudents = myDao.getAllStudents()
allStudents.observe(this) { // Observer::onChanged() 는 SAM 이기 때문에 lambda로 대체
val str = StringBuilder().apply {
for ((id, name) in it) {
append(id)
append("-")
append(name)
append("\n")
}
}.toString()
binding.textStudentList.text = str
}
Room 실습하기
- ID와 student name을 입력한 후 Add Student 버튼 클릭 시 Student List에 추가 되도록 함
- student name 입력 후 Query Student 버튼 클릭 시 Query Student를 확인
'TodayILearned > Android&Kotlin' 카테고리의 다른 글
사용자 위치 얻기 (0) | 2023.09.14 |
---|---|
안드로이드 앱의 기본 구조 (2) | 2023.09.14 |
SharedPreferences (4) | 2023.09.13 |
팀프로젝트 TIL (0) | 2023.09.07 |
팀프로젝트 TIL (0) | 2023.09.06 |