Как работать с RxJava и Retrofit с множественным доступом к базе данных Realm ORM и избежать доступа к Realm из неверного потока - PullRequest
1 голос
/ 22 марта 2019

Этот вопрос часто задают и разрешают разными способами, но если я возвращаюсь к тому же вопросу, то это потому, что я немного запутался.Я впервые имею дело с 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 голосов
/ 22 марта 2019

Я думаю, что я решаю проблему, создавая новый экземпляр 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 на имя по умолчанию

Любое решение приветствуется!

0 голосов
/ 22 марта 2019

Вы можете создать оболочку над областью, которая будет использовать 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.

...