どのように自動リフレッシュ領域のAndroidの内部マネージャ


Realm Androidのアプリで使用されるSQLのようなクエリの構文で埋め込まれたデータベースです.
その主な機能対他のデータベースは、あなたの携帯アプリのコード内のRealmオブジェクトがライブです.Realmオブジェクトを変更すると、アプリケーション全体のすべてのコピーが即座に更新され、Realm Change Listeners、Flow、RxJavaなどでオブジェクトの変更を再表示できます.

背景スレッドの問題


Realmのメカニズムは、あなたのRealmインスタンスが Looper thread , つまり、あなたActivity and Fragment クラス( UIスレッド).しかし、非UIバックグラウンドスレッドからRealmにアクセスする必要があるかもしれませんし、それらのインスタンスは自動更新されず、memory leak problems .
Realmを使う必要のある典型的な背景スレッドはAndroid WorkManager 労働者手動でRealmインスタンスを手動で更新することができますWorkManager 労働者は、私の経験では、これはほとんど手動でのリフレッシュ遅延のために動作しません(メモリリークと大きなrealmファイルの問題についての上のリンクを参照してくださいあなたのバックグラウンド領域が後ろに遅れ始めているときに発生する問題).

Realmをバックグラウンドスレッドで正しく使う方法


この問題を解決するために、私はWorkManagerワーカーズの中でRealmインスタンスを自動更新するために以下のテクニックを使用しました.
  • 仲間を作る HandlerThread バックグラウンド作業を実行するスレッドの場合は、ルーパーと Handler それに.これがLooper ここであなたの領域のインスタンスが住んでいます.
  • 使用するRealmHandlerThread‘s handler.post 排他的にすべてのあなたの領域の操作を実行します.このようにして、realmインスタンスは自動的にリフレッシュします.
  • class RealmHandlerThread(name: String) : HandlerThread(name) {
      @Volatile private var handler: Handler? = null
      @Volatile private var realm: Realm? = null
    
      fun startAndWaitUntilReady() {
        start()
        // HandlerThread's getLooper() blocks until it has a value
        handler = Handler(looper)
        handler?.post { realm = Realm.getDefaultInstance() }
      }
    
      private fun beforeQuit(onFinished: () -> Any): Boolean {
        if (looper == null) {
          return false
        }
        handler?.post {
          realm?.close()
          onFinished()
        }
        return true
      }
    
      override fun quit(): Boolean {
        return beforeQuit { super.quit() }
      }
    
      override fun quitSafely(): Boolean {
        return beforeQuit { super.quitSafely() }
      }
    }
    
  • handler.post 非同期なので、あなたの領域を同期的に使用することができますWorkManager Worker コード、ブリッジを非同期と同期の世界 suspendCoroutine .
  • class RealmHandlerThread(name: String) : HandlerThread(name) {
      ...
    
      suspend fun <T> executeWithRealm(realmFun: (Realm) -> T): T {
        return suspendCoroutine { continuation ->
          handler!!.post {
            try {
              continuation.resume(realmFun(realm!!))
            } catch (err: Exception) {
              continuation.resumeWithException(err)
            }
          }
        }
      }
      ...
    }
    
  • 最後にフックRealmHandlerThread CoroutineWorker .
  • abstract class RealmCoroutineWorker(
        name: String,
        context: Context,
        workerParams: WorkerParameters
    ) : CoroutineWorker(context, workerParams) {
    
      private val realmThread = RealmHandlerThread(name)
    
      abstract fun doWork(realm: Realm): Result
    
      final override suspend fun doWork(): Result {
        return withContext(Dispatchers.IO) {
          try {
            realmThread.startAndWaitUntilReady()
            realmThread.executeWithRealm { realm -> doWork(realm) }
          } catch (err: Exception) {
            Result.failure()
          } finally {
            realmThread.quit()
          }
        }
      }
    }
    

  • 利益!延長するRealmCoroutineWorker 得るWorkManager Worker これは、自動リフレッシュ領域インスタンスへの同期アクセスを楽しんでいます.
  • フルソースコード:
    import android.content.Context
    import android.os.Handler
    import android.os.HandlerThread
    import androidx.work.CoroutineWorker
    import androidx.work.WorkerParameters
    import io.realm.Realm
    import kotlin.coroutines.resume
    import kotlin.coroutines.resumeWithException
    import kotlin.coroutines.suspendCoroutine
    import kotlinx.coroutines.Dispatchers
    import kotlinx.coroutines.withContext
    
    abstract class RealmCoroutineWorker(
        name: String,
        context: Context,
        workerParams: WorkerParameters
    ) : CoroutineWorker(context, workerParams) {
    
      private val realmThread = RealmHandlerThread(name)
    
      abstract fun doWork(realm: Realm): Result
    
      final override suspend fun doWork(): Result {
        return withContext(Dispatchers.IO) {
          try {
            realmThread.startAndWaitUntilReady()
            realmThread.executeWithRealm { realm -> doWork(realm) }
          } catch (err: Exception) {
            Result.failure()
          } finally {
            realmThread.quit()
          }
        }
      }
    }
    
    class RealmHandlerThread(name: String) : HandlerThread(name) {
      @Volatile private var handler: Handler? = null
      @Volatile private var realm: Realm? = null
    
      fun startAndWaitUntilReady() {
        start()
        // HandlerThread's getLooper() blocks until it has a value
        handler = Handler(looper)
        handler?.post { realm = Realm.getDefaultInstance() }
      }
    
      suspend fun <T> executeWithRealm(realmFun: (Realm) -> T): T {
        return suspendCoroutine { continuation ->
          handler!!.post {
            try {
              continuation.resume(realmFun(realm!!))
            } catch (err: Exception) {
              continuation.resumeWithException(err)
            }
          }
        }
      }
    
      private fun beforeQuit(onFinished: () -> Any): Boolean {
        if (looper == null) {
          return false
        }
        handler?.post {
          realm?.close()
          onFinished()
        }
        return true
      }
    
      override fun quit(): Boolean {
        return beforeQuit { super.quit() }
      }
    
      override fun quitSafely(): Boolean {
        return beforeQuit { super.quitSafely() }
      }
    }
    
    前掲の記事https://pixelsandrobots.xyz/android/realm-auto-refresh-android-workmanager