Architecture Components란?
Android architecture components are a collection of libraries that help you design robust, testable, and maintainable apps.
유지보수를 쉽게하고 테스트 가능한 프로그램을 만들기위해 도움을주는 안드로이드 컴포넌트다.
Room 라이브러리
Room은 SQLite에 대한 추상화 레이어를 제공하여 원활한 데이터베이스 액세스를 지원하는 동시에 SQLite를 완벽히 활용한다.
SQLite를 API 직접사용하는것이 번거롭고 구조화되어있지도 않으니 Room을 사용한다.
SQLite를 API 직접사용하면 구조를 잘 잡지 않는이상 액티비티나 프래그먼트의 코드가 복잡해지고 뷰와 모델 등이 구분되어있지도 않아서 유지보수가 어렵다.
Entity
테이블이다. DB에 저장할 데이터 형식을 정의한다.
Dao(Data Access Object)
Enity를 조회, 수정, 삭제, 삽입을 할 수 있는 인터페이스.
Database에서 직접 sql쿼리문을 작성해서 사용하는 것보다 Dao를 이용하는 것을 추천한다.
Dao를 이용하면 sql문을 외부에서 알 필요도 없고(추상화), 때문에 testable하게된다. (의존성이 적을수록 mock하기가 좋음)
또한 Dao의 결과를 Entity class로 바로 받아볼 수 있기때문에 lower level sql 함수를 사용해서 sql결과를 객체로 바꾸는 번거로운과정을 거치지 않아도된다.
또한 Room라이브러리는 Dao의 쿼리문을 컴파일타임에 검사하기 때문에 디버깅도 쉽다.
Database
데이터베이스를 정의하고, Dao 인터페이스를 구현해 외부에 Dao를 제공하는 싱글톤 클래스.
Repository(옵션)
데이터베이스가 여러 종류가 있을때, 그것들을 묶어주는 역할(추상화)
액티비티나 프래그먼트 같은 뷰를 담당하는 컴포넌트로 하여금, 원하는 데이터가 어떤 데이터베이스에 있는지, 어떻게 가져와야하는지 신경쓰지않게해준다.
(예를들어 데이터가 내부디비에 있는지 웹서버에 있는지 신경쓰지않게해준다)
ViewModel
데이터베이스에서 데이터를 가져오는 메서드를 제공하고, 데이터를 관리한다.
화면이 회전될때 액티비티는 파괴되고, 재생성된다.
ViewModel에 데이터를 두면, viewModel은 액티비티가 파괴되고 재생성되는 동안에도 파괴되지않고 유지된다. 따라서 데이터를 관리하기에 적합하다.
View
viewModel이 갖고있는 데이터(LiveData)를 구독한다. 만약 데이터가 변경되면 View는 화면을 갱신한다.
LiveData는 옵저버패턴에서의 subject에 해당한다.
mNoteViewModel.getAllNotes().observe(this, Observer<List<Note>>{data -> data?.let { noteAdapter.setNotes(it) } })
이런식으로 옵저버를 생성해 라이브데이터의 observe 함수로 넘기면, 라이브데이터는 내부적으로 데이터가 변경했을떄 옵저버가 가진 콜백함수를 부르게된다.
* 참고로 이런것들을 구현하다보면 @Entity 라든지 @Dao 라든지 어노테이션이 많이 나오는데, 어노테이션은 코드에 대한 메타데이터 같은 것이여서, 예상컨데 Room라이브러리는 컴파일타임 혹은 런타임에 리플렉션을 이용해 어노테이션을 얻고 그에 따른 처리를 하는 것 같다. 예를들어
@Entity(tableName = "note_table")
data class Note(val title: String, val description: String, val priority: Int) {
@PrimaryKey(autoGenerate = true)
var id: Int = 0;
}
이렇게 테이블을 정의하면, Room 라이브러리가 내부sql에 쿼리를 해서 테이블을 만드는 듯하다.
또, 데이터베이스 클래스를 정의할때는 abstract로 정의하게된다. 그런데 getInstance에서 이 데이터베이스 클래스의 객체를 만들게된다.
@Database(entities = [Note::class], version = 1)
abstract class NoteDatabase : RoomDatabase() {
abstract fun noteDao() : NoteDao;
fun getInstance(context: Context): NoteDatabase =
INSTANCE ?: synchronized(NoteDatabase::class){
INSTANCE = Room.databaseBuilder(context.applicationContext, NoteDatabase::class.java, "note_database")
.fallbackToDestructiveMigration()
.addCallback(roomCallback)
.build();
return INSTANCE as NoteDatabase;
}
//생략
}
이게 가능한 이유는 Room.databaseBuilder이 abstract 메서드인 noteDao()를 구현하는 객체를 만들기 때문이다. 아마 리플렉션을 이용해서 abstract 메서드를 얻고, 무명객체 같은 형태로 NoteDatabase를 구현한뒤 반환하는 듯하다.
* 사족으로, 어노테이션은 그냥 마크고 어떤 로직도 포함하지 않는다.
'안드로이드 앱개발' 카테고리의 다른 글
Firebase를 이용해 FCM 구현하기(웹서버 이용) (0) | 2021.01.08 |
---|---|
브로드캐스트(android studio Broadcast) (0) | 2021.01.05 |
안드로이드 서비스 (0) | 2020.11.20 |
카메라로 사진찍기 (0) | 2020.10.27 |
파일입출력2 : 저장소 (Android Studio Internal/External Storage) (0) | 2020.10.27 |