【问题标题】:How to deal with RxJava and Retrofit with many access to Realm ORM database and avoid Realm access from incorrect thread如何通过对 Realm ORM 数据库的多次访问来处理 RxJava 和 Retrofit 并避免来自错误线程的 Realm 访问
【发布时间】:2019-03-22 13:57:27
【问题描述】:

这个问题经常被问到并以多种方式解决,但如果我回到同一个问题,那是因为我有点困惑。这是我第一次接触 Realm ORM。

数据库存储实现的这个存储库类状态。它以 Realm 和 ApiService 为实例

class LoginRepositoryImpl(var realm: Realm, var apiService: ApiService){
  override fun doLogin(email: String, password: String) {
     apiService.loginCheck(email, password)

            .flatMap { t: EntityToken ->

                // check if user already exist and delete it
                val checkIfUserExist = getUserIfExist("email", email)

                if (checkIfUserExist != null) {
                    realm.executeTransactionAsync {
                        checkIfUserExist.deleteFromRealm()
                    }

                }
                // insert user into DB
                realm.executeTransactionAsync { bgRealm ->
                    val user = bgRealm.createObject(UserModel::class.java, UserModel.cachedNextId)
                    user.email = email
                    user.logged = true
                }
                // i want to make another request to server
                return@flatMap apiService.pingServer(t.refresh_token)
            }
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({ uR ->
                // make update of user table
                 realm.executeTransactionAsync {
                    getUserIfExist("email", email)?.fullname = uR.fullname
                 }
            }
     }

   //function to check if user instance already exist
    private fun getUserIfExist(field: String, email: String): UserModel? {
       return realm.where(UserModel::class.java)
            .equalTo(field, email)
            .findFirstAsync()
}
}

Ps.帮我解决从错误线程访问领域

【问题讨论】:

    标签: android realm retrofit2 rx-java2


    【解决方案1】:

    您可以在将使用Schedulers.single() 的领域上创建包装器。它将每次都使用相同的线程。但我想我也必须从那个线程中获取 Realm 实例。 我做的很丑

    public long count() throws RealmException {
        return Single.fromCallable(() -> realmService.getRealm().where(dataTypeClass).count())
                .subscribeOn(Schedulers.single())
                .blockingGet();
    }
    

    realmService.getRealm() 返回仅延迟加载一次的 Realm 实例。

    您也可以只返回 Single 并使用 RxJava 链接调用。

    【讨论】:

      【解决方案2】:

      我认为我每次需要发出请求时都创建一个新的 Realm 实例来解决问题。

      我把我的私人功能变成了这个

       private fun getUserIfExist(db: Realm, email: String): UserModel? {
          return db.where(UserModel::class.java).equalTo("email", email).findFirst()
      }
      

      我为删除创建了一个新的私有函数

       private fun deleteInDb(db: Realm, email: String) {
          db.executeTransactionAsync {
              it.where(UserModel::class.java)
                  .equalTo("email", email)
                  .findFirst()
          }
      }
      

      为了写入表,我也创建了一个私有函数

       private fun writeToDB(entityToken: EntityToken, email: String): String? {
          realm = Realm.getDefaultInstance()
          realm.executeTransactionAsync { bgRealm ->
              var user = findInDb(bgRealm, email)
              if (user != null) {
                  deleteInDb(bgRealm, email)
              }
              user = bgRealm.createObject(UserModel::class.java, UserModel.cachedNextId)
              user!!.email = email
              user.token = entityToken.token
              user.refreshToken = entityToken.refresh_token
              user.logged = true
          }
          realm.close()
          return entityToken.refresh_token
      }
      

      最后我的 doLogin 函数变成了

      override fun doLogin(email: String, password: String) {
              apiService.loginCheck(email, password)
                  .subscribeOn(Schedulers.newThread())
                  .observeOn(Schedulers.computation())
                  .map {
                      // write to DB
                      writeToDB(it, email, password)
                      return@map it
                  }
                  .flatMap { ping ->
                      //doPing to refresh token if not success
                      if (!ping.success) {
      
                      }
                      return@flatMap apiService.userInfoFromServer
                  }
                  .observeOn(AndroidSchedulers.mainThread())
                  .subscribe({ uR ->
                      updateUserInfo(uR, email)
      
                  }, { error ->
                      Log.e("tt", error.message)
      
                  })
          }
      }
      

      它的作品,但我有另一个问题。我只发送 Realm Object 的事实,所以当我声明时

      realm = Realm.getDefaultInstance()
      

      它将我的 RealmConfiguration 的“数据库名称”更改为“默认名称”

      欢迎所有解决方案!

      【讨论】:

      • 数据库名称来自RealmConfiguration。
      猜你喜欢
      • 1970-01-01
      • 2016-10-29
      • 1970-01-01
      • 2018-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-22
      • 1970-01-01
      相关资源
      最近更新 更多