1. Room 라이브러리란?
- AAC(Android Architecture Component) 중 하나.
- SQLite DB를 보다 쉽게 사용할 수 있도록 하는 구글의 새로운 ORM(Object Relational Mapping)
(*ORM: DB 테이블과 매핑되는 객체를 만들고 그 객체에서 DB를 관리하는 프로그램)
https://developer.android.com/jetpack/androidx/releases/room
2. build.gradle (app) dependencies 추가
dependencies {
def room_version = "2.2.0-beta01"
implementation "androidx.room:room-runtime:$room_version"
// For Kotlin use kapt instead of annotationProcessor
annotationProcessor "androidx.room:room-compiler:$room_version"
// optional - Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:$room_version"
// optional - RxJava support for Room
implementation "androidx.room:room-rxjava2:$room_version"
// optional - Guava support for Room, including Optional and ListenableFuture
implementation "androidx.room:room-guava:$room_version"
// Test helpers
testImplementation "androidx.room:room-testing:$room_version"
}
참고: Kotlin 기반 앱의 경우 annotationProcessor 대신 kapt를 사용해야 합니다. 또한 kotlin-kapt 플러그인을 추가해야 합니다.
3. 개념
- Entity: DB에 저장할 데이터의 형식을 정의. 즉, DB의 테이블.
- DAO(Data Access Object): 데이터접근 객체, 즉 데이터베이스를 통해 수행할 작업(CRUD)을 함수로 정의한 클래스. DAO는 interface나 abstract class가 되야 함. 만약 abstract class로 만들면, 선택적으로 RoomDatabase객체를 생성자의 매개변수로 가질수 있으며 Room은 각 DAO의 구현을 컴파일 시간에 생성함.
- Room Database: DB를 생성하거나 버전을 관리하는 Room DB 객체. 해당 객체를 생성하는 비용이 많이 들기 때문에, 프로젝트에서 singleton으로 구현해야함.
4. 주의사항
- Room의 데이터는 모두 Background-Thread에서 처리해야함. 즉, Main-Thread에서의 DB접근을 허용하지 않음. 허용하고 싶다면 데이터베이스를 생성하는 빌더에서 allowMainThreadQueries()를 호출해야함.
- 허용하지 않는 이유는 데이터를 받아오는 작업이 길어질 경우 UI가 장시간 멈춰버릴수 있기 때문. 그래서 보통 비동기 쿼리를 하게 되는데 반환값으로는 LiveData 또는 RxJava의 Flowable으로 사용하는 경우가 많음.
5. 자세한 사용 예시
1) User라는 Entity 테이블을 만들 경우,
1
2
3
4
5
6
7
8
9
10
11
|
@Entity(tableName = "users")
public class User {
@PrimaryKey
public int uid;
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
public String lastName;
}
|
cs |
@Entity : 테이블로 사용할 클래스를 지정하는 annotation. 기본적으로 Room은 클래스이름을 데이터베이스의 테이블명으로 사용함.
그러나 만약에 다른 이름을 쓰고 싶다면 @Entity annotation에 tableName속성을 지정하면 됨
(ex. @Entity(tableName = "users")
@PrimaryKey : PK에 적용
@ColumnInfo : 앞서 설명한 테이블명처럼, 필드명을 별도로 지정하고 싶을 경우 사용하는 annotation. 지정하고싶지 않을 경우에는 생략 가능.
2) UserDao라는 DAO를 만들 경우,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
List<User> getAll();
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
@Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
"last_name LIKE :last LIMIT 1")
User findByName(String first, String last);
@Insert
void insertAll(User... users);
@Delete
void delete(User user);
@Update
void updateUsers(User... users);
}
|
cs |
@Dao : CRUD 작업을 정의할 interface를 지정하는 annotation
@Query: 컴파일 시간에 알맞은 쿼리인지를 입증하게 되고, 문제가 있을 시에는 컴파일 에러가 발생함.
Room은 또한 쿼리에 대한 반환값을 확인함.. 반환되는 객체의 필드의 이름이 만약에 대응되는 컬럼이름이 질의응답에서 일치하지 않는다면 Room은 다음과 같이 두가지 방법중 하나로 알림을 줌.
(1) 몇몇의 필드명만 일치하는 경우에는 경고 발생
(2) 일치하지 않는 필드명이 있을시 에러 발생
+ 이미 저장된 객체가 있을 경우에는 아래와 같이 덮어쓰기도 가능.
1
2
3
4
5
6
|
@Dao
public interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Person person)
}
|
cs |
- Room DB 객체
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
//Room Database Singleton
private static AppDatabase INSTANCE;
private static final Object sLock = new Object();
public static AppDatabase getInstance(Context context) {
synchronized (sLock) {
if(INSTANCE==null) {
INSTANCE=Room.databaseBuilder(context.getApplicationContext(),
AppDatabase.class, "Users.db") //Users.db == database-name
.build();
}
return INSTANCE;
}
}
}
|
cs |
보다 자세히 잘 나와있는 예시
https://codelabs.developers.google.com/codelabs/android-room-with-a-view/#0
Reference
https://black-jin0427.tistory.com/53
https://www.charlezz.com/?p=368
https://developer.android.com/training/data-storage/room/#java
'Dev > Android' 카테고리의 다른 글
[Android] Google Account Login(구글 계정 로그인 Api) 사용법 (1) | 2019.10.16 |
---|---|
[Android] SHA-1 fingerprint of keystore certificate (0) | 2019.10.16 |
[Android] App is not indexable by Google Search; consider adding at least one Activity with an ACTION-VIEW intent filter. (0) | 2019.10.10 |
[Android] LocationManager 사용법 (0) | 2019.10.02 |
[Android] SurfaceView - surfaceCreated, surfaceDestoryed (0) | 2019.09.26 |