개발/Android

Room Library, Paging Library

Debin 2022. 6. 2.
반응형

Android SQLite Database

  • 안드로이드에서는 SQLite 데이터베이스를 임베디드 데이터베이스로 제공한다.
  • SQLite DB는 경량급(Light-weight) 관계형 데이터베이스다.
  • 표준 SQL을 지원할 뿐만 아니라 데이터 조회 속도가 빨라 안드로이드, 아이폰 등에서 널리 사용한다.

Android Architecture Components

  • Google I/O 2017에서 안드로이드 개발에 필요한 새로운 라이브러리들을 Android Architecture Components(AAC)로 묶어 발표
  • 구글은 안드로이드 앱을 개발하면서 자주 만날 수 있는 문제들을 쉽게 해결할 수 있는 가이드를 개발자들에게 제공하기 위해 AAC를 제공한다.
  • AAC는 5개의 라이브러리로 구성한다.
    1. Lifecycles
    2. LiveData
    3. ViewModel
    4. Room
    5. Paging

구글에서 가이드하는 AAC 기반

Room

  • SQLite의 추상화 layer로 안드로이드 앱에서 SQLite 데이터베이스를 쉽고 편리하게 사용할 수 있도록 지원하는 ORM 라이브러리다.
  • ROOM은 다양한 Annotation을 통해 컴파일시 코드들을 자동으로 만들어주며 LiveData, RxJava와 같은 Observation 패턴을 지원한다.
  • Room은 3가지 컴포넌트로 구성된다. Databasem Entity, Dao로 구성된다.
  • 실습해봤는데 굉장히 JPA랑 유사하다고 느꼈다.

Room Components 구성 요소

  • Database: 데이터베이스 홀더를 포함하고, SQLite DB에 접근할 수 있는 액세스 포인트를 제공한다.
  • Entity: 데이터베이스의 테이블을 표현한다.
  • Dao : Data Access Objects의 줄임말로 데이터베이스에 접속하기 위한 메서드를 정의해 놓은 인터페이스다.

Room 특징

Annotation 기반의 정의와 자동 매칭

다양한 애노테이션으로 쉽게 Database, Entity, Dao 등을 정의할 수 있으며, 

세부 내용도 애노테이션을 이용해 약간의 Room 규약에 맞게 선언해주면,

Primary key, 쿼리 파라미터, 반환 타입 등을 자동으로 매칭한다.

컴파일 타임 쿼리 검증

Room은 런타임에서 확인이 가능한 쿼리 오류를 컴파일 타임에서 검증할 수 있다.

이부분도 Spring Data Jpa랑 비슷하다.

실시간 값 추적

Room은 LiveData와 연계하여 DB 트랜잭션을 실시간으로 모니터링(추적)할 수 있다.

Annotation(애노테이션)

  • 애노테이션은 자바 소스코드에 추가할 수 있는 메타 데이터로 클래스, 인터페이스, 메서드, 변수, 파라미터 등에 추가할 수 있다.
  • Annotation을 적재적소에 잘 사용하면 개발자의 코드를 단순화할 수 있다.
  • Annotation의 용도는 다음과 같다.
    • 컴파일러에게 코드의 문법을 체크하도록 정보를 제공한다.
    • IDE가 빌드할 때 코드를 자동으로 생성할 수 있도록 정보를 제공한다.
    • 실행 시 특정 기능을 실행하도록 정보를 제공한다.
  • Annotation은 컴파일러에 의해 생성되는 .class 파일에 포함되며, 그 클래스 파일을 통해 읽을 수 있다.

예시

@Entity 애노테이션으로 Data Class 선언

/* @Entity 정의 */
@Entity(tableName = "NoteEntity")
data class NoteEntity(
    @PrimaryKey(autoGenerate = true)
    var noteIdx: Int? = null,
    val noteContent: String
)

Dao 객체 선언

Data access에 사용할 메서드를 선언한다.

@Dao
interface NoteDao {
    /* Insert Annotation으로 Insert를 정의
       - key 중복시 Strategy 설정
       - 파라미터로 객체를 전달하면, 값 매칭은 Room이 인스턴스 변수를 보고 자동 처리
     */
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertNotes(vararg notes: NoteEntity)

    /* Query Annotation으로 쿼리를 정의
       - ROOM에서 제공하는 DataSource.Factory 를 사용하여 DataSource 인스턴스 생성
       - DataSource.Factory<key, value>
         . key: 데이터를 로드하는데 사용되는 식별자(페이지 번호)
         . value: 로드할 데이터의 타입(객체 타입)
    */
    @Query("SELECT * FROM NoteEntity ORDER BY noteContent ASC")
    fun selectNotes(): DataSource.Factory<Int, NoteEntity>

    /* Query Annotation으로 쿼리를 정의
       - 파라미터로 전달할 값을 콜론(:) 뒤에 같은 이름으로 선언(:noteIdx)
       - FROM 절로 넘긴 테이블과 매칭되는 모델로 반환값을 선언하면 room이 자동으로 객체를 매핑
     */
    @Query("SELECT * FROM NoteEntity WHERE noteIdx = :noteIdx")
    fun selectNote(noteIdx: Int): NoteEntity

    /* Update Annotation으로 Update를 정의
      - 파라미터로 객체를 전달하면, 값 매칭은 Room이 인스턴스 변수를 보고 자동 처리
    */
    @Update
    fun updateNote(vararg notes: NoteEntity)

    /*Delete Annotation으로 Delete를 정의
     - 파라미터로 객체를 전달하면, 값 매칭은 Room이 인스턴스 변수를 보고 자동 처리
   */
    @Delete
    fun deleteNots(vararg note: NoteEntity)
}

Database 생성

데이터베이스 생성을 위한 추상 클래스를 선언한다.

/* AppDatabse 선언 - RoomDatabase() 상속
   - entities 어노테이션으로 데이터베이스에 포함된 엔티티 목록 선언
   - 데이터베이스의 구조가 바뀌면 Version 변경
*/
@Database(entities = arrayOf(NoteEntity::class), version = 1)
abstract class AppDatabase : RoomDatabase() {

    /* DAO 클래스의 인스턴스를 반환하는 추상 메서드를 정의. */
    abstract fun noteDao(): NoteDao

}

Paging Library

  • App이 DB로부터 필요한 데이터를 페이지 단위로 읽어와 UI에 표시하는 것을 쉽게 구현하도록 도와주는 라이브러리다.
  • paging이란 컨텐츠를 특정 기준으로 범위를 나누고, 스크롤을 따라 page 단위로 load하는 것을 의미한다.

Paging 구현을 위한 3단계 작업

  1. 데이터를 Page 단위로 가져오기
  2. 데이터를 특정 기준으로 Page 나누기
  3. 중복 아이템 검사 후 UI 갱신

Paging Library 구성 요소

  • Paging Source 
    PagingSource는 데이터 스냅숏을 PagingData의 스트림으로 로드하기 위한 기본 클래스다.
  • PagingData
    페이지 단위로 나눈 데이터의 컨테이너 (데이터를 새로 고침할 때마다 상응하는 PagingData 생성)
  • PagingDataAdapter
    RecyclerView에 PagingData를 표시하는 RecyclerView.Adapter
    PagingDataAdapter는 페이지가 로드될 때 내부 Pagingdata 로딩 이벤트를 수신 대기하고,
    업데이트된 콘텐츠가 새로운 PagingData 객체 형태로 수신될 때 백그라운드 스레드에서 DiffUtil를 사용하여 중복 아이템인지 검사하고 UI를 갱신한다.

페이징 처리 과정

이상으로 포스팅을 마치겠습니다. 감사합니다.

 

 

 

참고자료

반응형

댓글