본문 바로가기

Android/AAC

[Android] Room 라이브러리

728x90

Room Library

  • AAC 중 하나
  • SQLite DB를 보다 쉽게 사용할 수 있도록 도와주는 ORM(Object Relational Mapping) 라이브러리

Room의 특징

  • 컴파일 도중 SQL에 대한 유효성 검사
  • 상용구 코드(Boiler Plate Code) 없이 매핑 가능
  • LiveData와 RxJava의 Flowable을 위한 observation으로 생성하여 동작 가능.

Room의 구성 요소

  1. Database : 데이터 베이스 객체. 객체를 생성하는 비용이 크기 때문에 Singleton으로 구현하는 것이 좋다.
  2. Entity : Database 내의 테이블
  3. Dao(Data Access Object) : 데이터 접근 객체. DB를 통해 수행할 작업(CRUD)을 함수로 정의한 클래스로 interface나 abstract class가 되어야 한다.

Room 사용을 위한 dependencies

    dependencies {
      def room_version = "2.2.5"

      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를 사용해야 한다.

 

Room 사용 예시

Entity

@Entity(tableName = "users")
public class User {
	@PrimaryKey(autoGenerate = true)
	public int id;
    
	@ColumnInfo(name = "names")
	public String name;
    
	public String number;   
}

 

@Entity : 테이블로 사용할 클래스를 지정하는 Annotation. tableName 속성을 추가하여 사용할 클래스 이름을 정할 수 있다. 위의 예제의 경우 users로 지정하여 사용하기 위해 tableName 속성을 추가한 것.

default 값으로 클래스 이름이 지정되며 대소문자를 구분하지 않기 때문에, 해당 속성을 사용하지 않고 선언하는 경우 user로 사용하면 된다.

 

@PrimaryKey : PK로 사용할 컬럼을 지정한다. autoGenerate 속성을 추가하면 자동으로 값을 증가시켜 저장한다는 의미이다.

 

@ColumnInfo : Entity의 tableName 속성처럼 필드명을 별도로 지정하고 싶을 때 사용하는 Annotation. name 속성의 값을 지정해주어 직접 필드명을 정의한다. 위의 예제의 경우 number은 그대로 사용하지만 name은 names로 이름을 재정의 했기 때문에 names로 사용해야 한다.

DAO

@Dao
public interface UserDao {
	@Query("SELECT * FROm users")
	List<User> getAll();
    
	@Insert(onConflict = OnConflickStrategy.REPLACE)
	void insertAll(User... users);
    
	@Delete
	void delete(User users);
    
	@Update
	void updateUsers(User... users);
}

 

@Dao : CRUD 작업을 정의할 interface 혹은 abstract class를 지정하는 Annotation

 

@Query : 실행할 쿼리문을 작성. 컴파일시 확인후 문제가 있으면 컴파일 에러 발생

 

@Insert, Delete, Update : 해당 작업에 해당하는 Annotation. 각각의 Annotaion에 onConflict 속성을 추가할 수 있다.

onConflict 속성은 해당 작업 중 충돌이 날 경우 어떻게 처리할지 명시한 것이다.

처리하는 방법은 총 5가지로, REPLACE, ROLLBACK, ABORT, FAIL, IGNORE 이 존재하며 필요에 따라 선택하여 속성 값을 주어 사용하면 된다.

Database 

@Database(entities = {User.class}, version = 1)
public abstract class SampleDatabase extends RoomDatabase {
	public abstract UserDao userDao();
    
	private static SampleDatabase instance;
    
	public static SampleDatabase getAppDatabase(Context context) {
		if(instance == null) {
			instance = Room.databaseBuilder(context, SampleDatabase.class,
				"User.db").build();
		}
		return instance;
	}
}

 

@Database : Database Annotation을 아용해 사용할 Entity를 입력 받는다.

 

Database를 구현할 때는 Singleton으로 구현해야 하기 때문에 예제와 같이 instance가 null일 경우 새롭게 생성하고 그렇지 않으면 가지고 있는 instance를 return 하여 사용하도록 하였다.

 

instance 객체를 생성할 때, allowMainThreadQueries()를 사용하여 Main Thread에서 DB 접근을 허용하도록 명시해줄 수 있지만, 권장하지 않는 방법이다.

데이터를 받아오는 작업이 길어질 경우 UI가 장시간 멈춰버릴 수 있기 때문이다.

따라서 Room 데이터는 모두 sub Thread에서 처리해야 하며, LiveData와 Flowable을 자주 사용한다.

728x90