如何通过对Realm ORM数据库的许多访问来处理RxJava和Retrofit,并避免来自错误线程的Realm访问

时间:2019-03-22 13:57:28

标签: android realm retrofit2 rx-java2

这个问题通常以很多方式被提出和解决,但是如果我回到同一问题,那是因为我有点困惑。这是我第一次处理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。帮助我解决来自错误线程的领域访问

2 个答案:

答案 0 :(得分:0)

您可以在将使用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链接调用。

答案 1 :(得分:0)

我认为我每次需要提出请求时都通过创建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对象的事实,所以当我声明

realm = Realm.getDefaultInstance()

它通过“默认名称”更改了我的RealmConfiguration“数据库名称”

欢迎所有解决方案!