개발하는 두더지

[Android/Kotlin] Realm+RecyclerView를 이용한 간단한 Todo 앱 만들기 본문

Kotlin

[Android/Kotlin] Realm+RecyclerView를 이용한 간단한 Todo 앱 만들기

덜지 2018. 12. 13. 11:40

Realm 데이터베이스를 활용한 간단한 Todo 리스트를 작성하고 리스트로 표현하고 수정하고 삭제하는 앱 만들기


Realm을 사용하기 위한 환경세팅

프로젝트 단위의 build.gradle 파일에 아래 코드를 작성해줍니다

dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath "io.realm:realm-gradle-plugin:5.2.0"
}

앱 단위의 build.gradle 파일에 아래 코드를 작성해줍니다

apply plugin: 'realm-android'

apply plugin: 'kotlin-kapt'


Sync Project with Gradle Files 를 눌러주면 Realm을 사용할 수 있는 상태가 됩니다.


Realm 초기화

Realm을 초기화하는 건 간단합니다. Application 파일을 만든뒤 init 함수를 호출시키면 됩니다. Realm API를 사용하기전에 반드시 호출되어야 하며, 라이브러리를 초기화하고 기본적인 세팅을 완료하여 사용할 준비를 만들어 줍니다.

class MyApplication: Application() {
override fun onCreate() {
super.onCreate()
Realm.init(this)
}
}


Todo 데이터 모델을 하나 만들어줍니다. RealmObject 클래스를 직접 사용하는 것 대신 상속하여 사용합니다.

open class Todo(
@PrimaryKey var id: Long = 0,
var title: String = "",
var date: Long = 0
): RealmObject()

고유키로 사용하기위해 primaryKey 어노테이션을 사용합니다. 하지만 id 값이 자동으로 증가되지않기 때문에 데이터 객체를 만들때 수동으로 id값을 증가시켜서 사용해야 합니다.


MainActivity는 db에서 저장된 데이터를 내림차순으로 받아서 TodoAdapter의 list에 저장하는 역할을 하고,

EditActivity는 새로운 할일을 작성하고 저장하거나, 이미 만들어진 할일을 수정하거나 삭제하는 역할을 합니다.

TodoAdapter는 추가된 리스트를 보여주기위해 준비하는 역할을 합니다. 아이템의 타입에따라 어떤 xml 레이아웃으로 보여줄지 뷰홀더 타입을 정하고, 뷰홀더 패턴에따라 뷰를 재사용할 때 아이템을 다시 세팅하는 작업을 합니다.


Realm 트랜잭션

Realm을 사용할 준비가 되었으니 직접 사용해 봅니다. getDefaultInstance 팩터리 메서드를 통해 이미 만들어진 realm 객체에 접근하게 됩니다. Realm.getDefaultInstanceRealm.init 메서드는 모두 정적 팩터리 메서드입니다. 

private val realm = Realm.getDefaultInstance()


중간에 RealmConfiguration빌더패턴으로 객체를 생성하여 Realm에 static으로 선언되어있는 defaultConfiguration 객체를 초기화 해줍니다. Realm.getDefaultInstance 메서드는 defaultConfiguration 객체를 리턴받고 null이 아니라면 새로운 Realm 인스턴스를 만들거나 현재 스레드에서 존재하는 인스턴스를 반환시켜줍니다.

public static synchronized void init(Context context) {
if (BaseRealm.applicationContext == null) {
//noinspection ConstantConditions
if (context == null) {
throw new IllegalArgumentException("Non-null context required.");
}
checkFilesDirAvailable(context);
RealmCore.loadLibrary(context);
setDefaultConfiguration(new RealmConfiguration.Builder(context).build());
ObjectServerFacade.getSyncFacadeIfPossible().init(context);
if (context.getApplicationContext() != null) {
BaseRealm.applicationContext = context.getApplicationContext();
} else {
BaseRealm.applicationContext = context;
}
OsSharedRealm.initialize(new File(context.getFilesDir(), ".realm.temp"));
}
}
public static Realm getDefaultInstance() {
RealmConfiguration configuration = getDefaultConfiguration();
if (configuration == null) {
if (BaseRealm.applicationContext == null) {
throw new IllegalStateException("Call `Realm.init(Context)` before calling this method.");
} else {
throw new IllegalStateException("Set default configuration by using `Realm.setDefaultConfiguration(RealmConfiguration)`.");
}
}
return RealmCache.createRealmOrGetFromCache(configuration, Realm.class);
}

이렇게 액티비티마다 새로운 Realm 인스턴스를 만들지않고 재사용해서 사용합니다.


데이터를 추가하는 부분을 살펴보겠습니다. beginTransaction으로 트랜젝션이 시작되었음을 알리고 commitTransaction으로 작업한 내용을 commit하고 완료합니다. 이 사이의 모든 작업을 하나의 트랜잭션으로 간주합니다. 

realm.beginTransaction()

val newItem = realm.createObject<Todo>(nextId())
newItem.title = todoEditText.text.toString()
newItem.date = calendar.timeInMillis

realm.commitTransaction()


Realm 종료

close 메서드를 통해서 Realm 인스턴스를 종료시켜줍니다. 메모리 릭을 피하기 위해 반드시 작업이 끝나면 종료시켜줘야 합니다. 

override fun onDestroy() {
super.onDestroy()
realm.close()
}


Todo 데이터를 가져와서 리사이클러뷰에 보여주는 과정을 살펴보겠습니다. where, findAll, sort 메서드가 사용됐는데 Todo타입의 모든 객체를 받아서 내림차순으로 정렬하여 OrderedRealmCollectionImpl 하위 컬렉션으로 반환시켜줍니다. 

val realmResult: RealmResults<Todo> = realm.where<Todo>()
.findAll()
.sort("date", Sort.DESCENDING)


컬렉션 타입이기 때문에 iterator를 이용한 루프문으로 사용할 수 있습니다.

for(Todo in realmResult) {
// work!
}

그리고 Realm 모델 객체가 변화가 발생하면 바로 이벤트를 받을 수 있도록 리스너도 설정할 수 있습니다. 

realmResult.addChangeListener { _ ->
adapter.notifyDataSetChanged()
}



전체 소스코드도 링크걸어두었으니 더 궁금하신 내용은 참고하시면 됩니다.


참고

realm java example




Comments