[안드로이드스튜디오_문화][Realm]

기말 지하기포·2023년 12월 8일
0

#Realm 공식문서
=>https://realm.io/

#Realm
-MongoDB에서 개발하였으며 Realm Kotlin으로 안드로이드에서 사용 할 수 있고 , 백엔드와 실시간 데이터 동기화가 가능하다.

-Realm은 별도의 데이터베이스를 포함해서 앱의 APK 크기를 3~4MB 증가시키기 때문에 앱의 다운로드 크기에 영향을 미칠 수 있다.

-Realm은 객체 지향적 접근 방식을 채택하였기 때문에 데이터를 다루기 쉽게 하며 , Room 보다 더 직관적이기 때문에 개발자가 코드를 작성하고 유지 관리하기 쉽다.

-아래글에는 RealmDatabse 객체와 RealmDatabase 이 두가지의 단어가 나오는데 , RealmDatabase 객체가 의미하는 것은 메모리상에 존재하는 RealmDatabase에 들어가기 전의 데이터를 의미하고 , RealmDatabase는 실제 데이터들을 관리하는 RealmDatabase를 의미한다. 즉, RealmDatabase는 여러개고 RealmDatabase는 유일하다. 그래야지 앱 전역에서 데이터를 동일하게 관리 할 수 있기 때문이다.

-프로젝트 수준의 build.gradle의 plugins에 추가하기

plugins {

    id("io.realm.kotlin") version "1.11.0" apply false

}

-모듈 수준의 build.gradle의 plugins , 종속성 추가하기

plugins {

    id("io.realm.kotlin")

}

dependencies {

    implementation("io.realm.kotlin:library-base:1.11.0")
}

Realm Database 만들기

-RealmDatabase 객체를 만드는 방법은 다음과 같은 두 종류가 있다. 다음 두가지의 방법[1.RealmObject] , [2.EmbeddedRealmObject]를 통해서 RealmDatabase를 만들어준다.

-[1.RealmObject] :
-RealmObject를 상속받은 클래스는 RealmDatabase에 저장하려는 모델을 정의한다. 이렇게 생성된 클래스의 객체는 RealmDatabase 내부의 독립적인 엔트리로 존재하며, 각각의 객체들은 고유한 ID를 통해 구별된다.

-RealmObject RoomDatabase의 테이블과 유사한 개념인데, 관계형 데이터베이스의 개념을 객체 지향적 개념으로서 사용 할 수 있게 해준다. 즉, 데이터 테이블 객체를 직접 다루는 것처럼 데이터에 쉽게 접근해서 처리 할 수 있다.

  • RealmObject를 통해서 RealmDatabase 클래스 생성하는 예시코드(1)
class Course : RealmObject {
	@PrimaryKey
    var _id : ObjectId = ObjectId()
    var name : String = ""
    var teacher : Teacher? = null
    var enrolledStudents : RealmList<Student> = realmListOf()

-[2.EmbeddedRealmObject]
-EmbeddedRealmObject를 상속받은 클래스의 객체는 다른 RealmObject에 내장 될 수 있으며, 해당 객체는 독립적인 RealmDatabase객체가 아니라 항상 부모 RealmDatabse의 일부로서 존재한다.

-EmbeddedRealmObject를 상속받은 클래스 객체는 부모 RealmObject와 생명주기를 공유한다. cf. 데이터 베이스의 중첩이라고 생각하면 된다.

  • EmbeddedRealmObject를 통해서 RealmDatabase 클래스 생성하는 예시코드(1)
class Student : EmbeddedRealmObject {
    var class : Int = 0
    var teacher : String = ""
    var city : String = ""
    var name : String = ""    
}

-[3.RealmDatabase를 구성할 때 자주 사용되는 주요 인퍼페이스 및 클래스 및 함수]
-RealmList<> : RealmObject 내부에서 (1:N)관계를 모델링 할 때 사용된다. 관리모드(managed)와 비관리모드(unmanaged)가 있으며 , 관리모드에서는 RealmList가 RealmDatabase에 자동으로 저장되고 동기화된다. 또한 비관리모드는 그냥 평범한 List와 동일하다고 보면된다. 관리모드라는 것은 "RealmList가 RealmObject내부에 있음"을 의미하는 것이고 그 외의 것들은 비관리모드이다. 타입은 RealmObject 객체여야 하고, 해당 타입을 리스트로 받아와야 한다.

-RealmResult<> : RealmDatabase의 결과를 나타낸는 컬렉션으로서 "<>" 내부에 들어갈 수 있는 타입은 RealmObject의 객체여야 한다. RealmResult는 실시간으로 RealmDatabase의 객체가 변경될 때 flow로 방출되면서 RealmResult를 통해서 결과를 받아오는 것이다.

Realm 초기화해주기

-Application()을 상속받은 MyApp 클래스에 Realm을 초기화하는 코드를 작성해주고 AndroidManifest.xml에 Application 관련 선언을 해준다.

-아래 코드에서 companion object에서 Realm을 선언해준 것은 싱글톤 객체로서 정의함으로서 코드상에서 사용되는 Realm 객체는 단 하나 뿐이다. 또한, 지연 초기화 lateinit 키워드를 사용함으로서 해당 변수인 realm이 선언 시점이 아니라 실행 시점에 초기화 될 것이라고 알려준다.

  • RealmDatabase 초기화 예시코드(1)
class MyApp: Application() {
    companion object {
        lateinit var realm: Realm
    }
    override fun onCreate() {
        super.onCreate()

        realm = Realm.open(
            configuration = RealmConfiguration.create(
                schema = setOf(
                    Address::class,
                    Teacher::class,
                    Course::class,
                    Student::class,
                )
            )
        )

    }
}

-실제로 RealmDatabase를 사용하려는 곳에 아래와 같은 코드를 넣어서 사용하면 된다.

    private val realm = MyApp.realm

Realm.open 메서드 설명

-Realm.open(configuration)의 configuration parameter에 RealmConfigutaion.create의 결과값을 넣어줘야 한다. 아래코드는 RealmDatabase 클래스들로 구성된 RealmDatabase를 설정하는 데 도와주는 객체를 생성한다.

// 아래코드를 Realm.open()의 parameter에 넣어준다.
RealmConfiguration.create(
	schema = setOf(
    	RealmDatabase 객체 (1)::class,
        RealmDatabase 객체 (1)::class,
        .
        .
        .
        RealmDatabase 객체 (n)::class
    )
)

RealmDatabse의 데이터 처리 메서드

realm.write(suspend function){}

-realm.write{} 블록 내부의 코드가 완료되년 모든 변경사항은 RealmDatabase에 대한 변경사항을 안전하게 반영한다.

-realm.write{} 블록 내부에서 RealDatabase 객체에 대한 변경을 처리해야지 오류가 발생하지 않고 안전하게 작동한다. 반드시 realm.wire{} 블록 내부에서 데이터에 접근해야 한다.

-RealmDatabase에 데이터를 추가 할 때는 realm.write{}의 코드 블락 내부에 작성하면된다. 예를들어 Address()라는 RealmDatabase 객체가 있을 때 해당 객체의 property에 내가 원하는 값을 넣어준 후 해당 객체를 특정 변수에 넣어주면 된다. 즉, RealmDatabase 객체 하나 하나가 Room의 Table 역할을 하는 것의 의미이며 아래에 예시코드가 존재한다.

// RealmDatabase에 데이터 넣는 방법[1]
// 아래는 Address 클래스의 property를 한 번에 넣어주는 방법이다.
// 즉, RealmDatabse에 Data를 한 번에 넣는 방법

class Address: EmbeddedRealmObject {
    var fullName: String = ""
    var street: String = ""
    var houseNumber: Int = 0
    var zip: Int = 0
    var city: String = ""
    var teacher: Teacher? = null
}


realm.write {
	val address1 = Address().apply {
		fullName = "John Doe"
		street = "John Doe Street"
		houseNumber = 24
		zip = 12345
		city = "Johncity"
	}
}
    
// RealmDatabase에 데이터 넣는 방법[2]
// 아래는 Course 클래스의 property를 한 번에 넣어주는 방법이다.
// 아래처럼 Course 객체를 하나 생성하고 해당 객체의 property에 개별적으로 데이터를 넣을 수 있다.

class Course: RealmObject {
    @PrimaryKey
    var _id: ObjectId = ObjectId()
    var name: String = ""
    var teacher: Teacher? = null
    var enrolledStudents: RealmList<Student> = realmListOf()
}


realm.write {

// Course Class의 name에 데이터를 넣어주는 방법
val course1 = Course().apply {
	name = "강의1"
}

// Course Class의 teacher에 데이터를 넣어주는 방법
course1.teacher = teacher1

// Course Class의 enrolledStudents에 데이터를 넣어주는 방법
course1.enrolledStudents.add(student1)

}
     

copyToRealm(RealmDatabase객체 , Update 정책)

-Data를 RealmDatabase에 추가 또는 업데이트를 한다.

-RealmDatabase에 해당 RealmDatabase 객체를 넣어줌으로서 , 기존에 메모리에만 존재하던 RealmDatabase객체(관리되지 않는 객체)를 RealmDatabase에 저장하고 저장된 객체를 관리하는 인스턴스를 반환한다.

-이로서 객체가 Database에 저장됨과 동시에 실제로 앱에서 객체의 변경사항을 앱에서 실시간으로 받아서 사용 할 수 있다.

-Update정책은 크게 두 가지가 존재하고 , UpdatePolicy.ERROR은 해당 객체가 이미 존재할 경우에는 에러를 발생시킨다. 즉, 중복된 객체가 이미 존재한다면 새 객체를 추가하지 않고 에러를 던져서 객체를 RealmDatabase에 중복으로 추가하는 것을 방지 할 수 있다.

-UpdatePolicy.ALL은 새로운 객체를 추가 할 때 또는 이미 데이터 베이스에 존재하는 객체의 경우 해당 객체를 업데이트 하려고 할 때 사용한다. 객체에 할당된 프라이머리 키를 기준으로 기존 데이터를 판별하고 , 기존 데이터가 있을 경우 새 데이터로 교체한다. 이로서 기존 데이터를 최신의 상태로 유지하고자 할 때 사용한다.

delete()

-Data를 RealmDatabase에서 삭제 시킨다.

-findLatest()는 RoomDatabase의 최신의 객체를 반환한다.

  • delete()의 예시코드(1)
fun deleteCourse() {
        viewModelScope.launch {
            realm.write {
                val course = courseDetails ?: return@write
                val latestCourse = findLatest(course) ?: return@write
                delete(latestCourse)

                courseDetails = null
            }
        }
    }

-

profile
포기하지 말기

0개의 댓글