MongoDB.local SF, Jan 15: See the speaker lineup & ship your AI vision faster. Use WEB50 to save 50%
Find out more >
Docs Menu
Docs Home
/ /
Atlas Device SDK

LiveData로 빠른 시작 - Java SDK

이 페이지에는 LiveData 를 사용하는 예시 Android 애플리케이션 에 Realm 빠르게 통합하는 방법에 대한 지침이 포함되어 있습니다. 이 예시 애플리케이션 사용하면 사용자가 버튼을 사용하여 카운터를 증가시킬 수 있습니다.

이 빠른 시작 가이드 에서는 동기화 를 사용하여 클라이언트 간의 데이터 변경 사항을 동기화합니다. 시작하기 전에 다음 사항이 있는지 확인하세요.

참고

동기화 없이 LiveData 사용

동기화 없이 이 퀵스타트를 사용하려면 SDK에서 동기화 기능을 비활성화하세요. 앱 수준 build.gradle 파일에서 다음 줄을 제거하면 됩니다.

realm {
syncEnabled = true
}

줄을 제거한 후 Gradle 구성을 다시 동기화하여 Java SDK를 오프라인 전용 상태로 다시 로드합니다. 동기화 없이 Java SDK를 사용하려면 CounterModel 파일에서 동기화 구성, 사용자 로그인, 파티션 값 가져오기 및 사용과 관련된 줄을 제거하세요.

시작하려면 예시 리포지토리를 로컬 환경에 복사합니다.

필요한 대부분의 코드가 포함된 Android 애플리케이션을 이미 구성했습니다. GitHub에서 직접 클라이언트 애플리케이션 리포지토리를 복제할 수 있습니다.

git clone https://github.com/mongodb-university/realm-android-livedata.git

리포지토리에는 finalstart 의 두 가지 브랜치가 포함되어 있습니다. final 브랜치는 사용자가 이 튜토리얼을 완료 한 후 처리해야 하는 앱의 완성된 버전입니다. 이 튜토리얼을 진행하려면 start 브랜치를 확인하세요.

git checkout start

이제 리포지토리를 복제했으므로 Java SDK 및 Android LiveData를 실행하는 데 필요한 종속성을 추가해야 합니다. 프로젝트 레벨 build.gradle 파일의 buildscript.dependencies 블록에 Java SDK 종속성을 추가하는 것으로 시작합니다.

buildscript {
ext.kotlin_version = "1.4.10"
repositories {
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:4.0.2"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "io.realm:realm-gradle-plugin:10.2.0"
}
}

또한 앱 수준 build.gradle 파일의 dependencies 블록에 Android LiveData 종속성을 추가해야 합니다.

dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.1'
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

그런 다음, 앱 수준 build.gradle 파일에 다음과 같은 최상위 블록을 생성하여 SDK에서 동기화를 활성화합니다.

realm {
syncEnabled = true
}

그런 다음 앱 수준 build.gradle 파일의 android 블록에 다음 블록을 만들어 DataBinding을 활성화합니다.

android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
defaultConfig {
applicationId "com.mongodb.realm.livedataquickstart"
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildFeatures {
dataBinding true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}

마지막으로 '동기화' 버튼을 클릭하거나 애플리케이션 메뉴에서 Build > Rebuild Project 를 선택하여 이러한 변경 사항으로 Gradle 구성을 재구성하고 종속성을 가져옵니다.

With all of the dependencies in place, it's time to create a LiveData-compatible interface for our Realm objects. 이렇게 하려면 몇 가지 이벤트를 처리해야 합니다.

  • onActive() 메서드를 사용하면 관찰자가 변경 리스너를 추가하여 기본 Realm 객체에 대한 변경 사항을 구독할 수 있습니다.

    override fun onActive() {
    super.onActive()
    val obj = value
    if (obj != null && RealmObject.isValid(obj)) {
    RealmObject.addChangeListener(obj, listener)
    }
    }
  • onInactive() 메서드를 사용하면 관찰자가 변경 리스너를 제거하여 기본 Realm 객체에 대한 변경 사항에 대한 구독을 취소할 수 있습니다.

    override fun onInactive() {
    super.onInactive()
    val obj = value
    if (obj != null && RealmObject.isValid(obj)) {
    RealmObject.removeChangeListener(obj, listener)
    }
    }
  • 변경이 발생하면 listener 멤버는 LiveData 상위 클래스의 null setValue() 메서드를 사용하여 Realm 객체가 삭제되지 않는 한 Realm 객체의 값을 UI에 전달하며, 변경 리스너는 다음 값을 전달합니다. 을 사용하여 유효하지 않게 삭제된 객체에 대한 참조를 전달하는 대신

    private val listener =
    RealmObjectChangeListener<T> { obj, objectChangeSet ->
    if (!objectChangeSet!!.isDeleted) {
    setValue(obj)
    } else { // Because invalidated objects are unsafe to set in LiveData, pass null instead.
    setValue(null)
    }
    }

RealmResults와 함께 LiveData 사용

이 예시 LiveData만 사용하여 RealmObjects UI 에 를 표시합니다. 를 표시하는 샘플 구현 RealmResults LiveRealmResults를 참조하세요.

이 애플리케이션은 모든 로직과 핵심 데이터를 CounterModel 이라는 ViewModel 내에 저장합니다. 애플리케이션이 실행되면 애플리케이션이 닫힐 때까지 사용되는 CounterModel 인스턴스가 생성됩니다. 해당 인스턴스에는 애플리케이션의 UI에 표시되는 LiveData가 포함되어 있습니다. LiveData의 인스턴스를 생성하려면 Realm에 저장된 Counter 객체에 액세스하여 이를 LiveRealmObject 생성자에 전달해야 합니다. 이를 위해 다음을 수행합니다.

  1. 앱 ID 를 사용하여 앱에 연결합니다.

  2. 사용자를 인증합니다.

  3. 동기화를 사용하여 특정 영역에 연결합니다.

  4. Counter 에 대한 영역을 쿼리하고, 이 영역에 아직 생성되지 않은 경우 새 Counter 를 삽입합니다.

  5. Counter 인스턴스를 사용하여 LiveRealmObject 를 인스턴스화하고 CounterModelcounter 멤버에 저장합니다.

다음 코드 스니펫은 이 동작을 구현합니다:

init {
val appID = "YOUR APP ID HERE" // TODO: replace this with your App ID
// 1. connect to the MongoDB Realm app backend
val app = App(
AppConfiguration.Builder(appID)
.build()
)
// 2. authenticate a user
app.loginAsync(Credentials.anonymous()) {
if(it.isSuccess) {
Log.v("QUICKSTART", "Successfully logged in anonymously.")
// 3. connect to a realm with Realm Sync
val user: User? = app.currentUser()
val partitionValue = "example partition"
val config = SyncConfiguration.Builder(user!!, partitionValue)
// because this application only reads/writes small amounts of data, it's OK to read/write from the UI thread
.allowWritesOnUiThread(true)
.allowQueriesOnUiThread(true)
.build()
// open the realm
realm = Realm.getInstance(config)
// 4. Query the realm for a Counter, creating a new Counter if one doesn't already exist
// access all counters stored in this realm
val counterQuery = realm!!.where<Counter>()
val counters = counterQuery.findAll()
// if we haven't created the one counter for this app before (as on first launch), create it now
if (counters.size == 0) {
realm?.executeTransaction { transactionRealm ->
val counter = Counter()
transactionRealm.insert(counter)
}
}
// 5. Instantiate a LiveRealmObject using the Counter and store it in a member variable
// the counters query is life, so we can just grab the 0th index to get a guaranteed counter
this._counter.postValue(counters[0]!!)
} else {
Log.e("QUICKSTART", "Failed to log in anonymously. Error: ${it.error.message}")
}
}
}

중요

UI 스레드에서 읽기 또는 쓰기 안 함

데이터베이스 읽기 및 쓰기는 계산 비용이 많이 들기 때문에 SDK는 기본적으로 UI 스레드에서 읽기 및 쓰기를 비활성화합니다. 간단하게 설명하기 위해 이 예시에서는 allowWritesOnUiThread()allowQueriesOnUiThread() 구성 빌더 메서드를 사용하여 UI 스레드 읽기 및 쓰기를 활성화합니다. 프로덕션 애플리케이션에서는 거의 항상 비동기 메서드를 사용하여 백그라운드 스레드에 대한 읽기 및 쓰기를 연기해야 합니다.

에 저장된 데이터를 CounterModel 애플리케이션 UI 에 표시하려면 CounterModel 애플리케이션 을 생성할 때 viewModels() 메서드를 사용하여 싱글톤 CounterFragment 액세스 해야 합니다. 모델을 인스턴스화한 후에는 Android 데이터 바인딩 라이브러리를 사용하여 모델의 데이터를 UI 요소에 표시할 수 있습니다.

애플리케이션이 CounterFragment 을 생성할 때 CounterModel 싱글톤에 액세스하려면 CounterFragmentonCreateView() 메서드에 다음 코드를 배치합니다.

val model: CounterModel by viewModels()

다음으로, UI에서 카운터 프래그먼트에 대한 데이터 바인딩 후크를 설정합니다.

<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="counterModel"
type="com.mongodb.realm.livedataquickstart.model.CounterModel"
/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CounterFragment">
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{counterModel.counter.value.get().toString()}"
android:textSize="58pt"
app:layout_constraintBottom_toTopOf="@id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textview" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

마지막으로 모델을 바인딩에 연결하여 UI에서 카운터를 표시하고 CounterFragmentonCreateView() 메서드에서 다음 코드를 사용하여 버튼을 누를 때 카운터를 반복합니다.

val binding = CounterFragmentBinding.inflate(inflater, container, false).apply {
lifecycleOwner = viewLifecycleOwner
counterModel = model
}
binding.root.button.setOnClickListener {
Log.v("QUICKSTART", "Clicked increment button. Current value: ${model.counter.value?.value?.get()}")
model.incrementCounter()
}
return binding.root

이제 샘플 애플리케이션을 실행할 수 있습니다. You should see an interface that looks something like this:

LiveData 퀵스타트 카운터 앱.

'추가' 버튼을 클릭하면 카운터 값에 1이 추가됩니다. 동기화를 사용하면 앱 로그를 확인하여 개별 증분 이벤트를 확인할 수 있습니다. Android LiveData는 수명 주기를 인식하므로 화면을 회전하거나 기기의 RAM을 비워 애플리케이션 상태를 해제해도 애플리케이션 상태에 영향을 주지 않아야 하며, 애플리케이션 상태는 원활하게 재개되고 재개 시 모델 싱글톤에 저장된 상태를 사용하여 이벤트를 자동으로 자동으로 다시 구독해야 합니다. 캡슐화된 LiveData 인스턴스.

  • Android LiveData에 라이브 Realm 데이터를 캡슐화하기 위한 템플릿으로 LiveRealmObjectLiveRealmResults 클래스를 사용합니다.

  • ViewModel을 사용하여 해당 데이터를 표시하는 UI 요소에서 기본 데이터를 분리합니다.

  • DataBinding을 사용하면 활동 또는 프래그먼트에서 명시적으로 값을 설정하지 않고도 모델 데이터와 UI 요소 간의 관계를 선언할 수 있습니다.

이 빠른 시작 가이드가 도움이 되었나요? 페이지 오른쪽에 있는 피드백 양식을 통해 알려주세요!

다음

Atlas Device SDK Docs에 오신 것을 환영합니다

이 페이지의 내용