Realm, сетевые операции, подписка и наблюдение за разными потоками с помощью RxJava

Мне необходимо :

  • Получить некоторые данные из API в фоновом потоке
  • Отображение данных в пользовательском интерфейсе
  • Сохранить в Realm.

    fetchItemsFromServer().subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<ItemList>() {
        @Override
        public void call(ItemList items) {
    
            displayItems(items);
    
            try {
                realm.beginTransaction();
                realm.copyToRealmOrUpdate(itemList);
                realm.commitTransaction();
                Logger.v("Realm ", "Copied list object to realm");
            } catch (Exception e) {
                Logger.e("Realm Something went wrong ", e);
                realm.cancelTransaction();
            }
    
        }
    }
    

Это вызывает ошибку: доступ к области из неправильного потока

У меня есть 4 вкладки, получающие разные сообщения одновременно.

fetchItemsFromServer() — это интенсивный вызов, и ограничивать этот вызов одним потоком нехорошо. Мне нужна эта гибкость.

Кто-нибудь нашел обходные пути, используя область таким образом?

Например, большинство примеров, как правило, сосредоточены на выборке из Realm, а не на работе с сетевыми операциями:

Пример ниже:

Rxjava — https://realm.io/news/realm-java-0.87.0/

Использование области с RxJava — https://realm.io/news/using-realm-with-rxjava/ (предыдущее решение, но с недостатками производительности)

My Realm предоставляется модулем базы данных посредством внедрения зависимостей (Dagger 2)

@Module
public class DatabaseModule {

    public static final String REALM_FILE_NAME = "Realm name";

    @Provides
    Realm providesRealmInstance(Context context) {
    return Realm.getInstance(
            new RealmConfiguration.Builder(context)
                    .name(REALM_FILE_NAME)
                    .build());
    }
}

person AndroidEnthusiast    schedule 14.01.2016    source источник
comment
Откуда вы получаете свой экземпляр Realm в подписчике? Подписчик выполняет сохранение в потоке пользовательского интерфейса, поэтому, если ваш экземпляр Realm также был создан там, он должен работать.   -  person Christian Melchior    schedule 15.01.2016
comment
@ChristianMelchior мое царство вводится через внедрение зависимостей. как только я удаляю subscribeOn(Schedulers.io()) для вызова API, все работает нормально.   -  person AndroidEnthusiast    schedule 15.01.2016
comment
Удаление subscribeOn(Schedulers.io()) не должно повлиять на вашего подписчика, так как вы observeOn основной поток. Ваш fetchItemsFromServer() каким-то образом использует Realm?   -  person Christian Melchior    schedule 15.01.2016
comment
@ChristianMelchior нет, он вызывает запрос, который возвращает элементы в виде Json, использует Gson для анализа в объект области, ItemList   -  person AndroidEnthusiast    schedule 15.01.2016
comment
Тогда моя лучшая идея заключается в том, что Dagger каким-то образом предоставляет вам кэшированную версию из другого потока. Обратите внимание, что если вы настроите свой Realm, как в примере, вы можете избежать Dagger, используя setDefaultConfiguration в своем классе Application и используя Realm.getDefaultInstance() для создания экземпляра.   -  person Christian Melchior    schedule 15.01.2016
comment
Кстати, когда и где вы вводите экземпляр Realm?   -  person Christian Melchior    schedule 15.01.2016
comment
@ChristianMelchior Компонент моего приложения встроен в мой класс приложения, а затем может быть внедрен в действия, фрагменты и т. д. Вы не возражаете, если мы перенесем это в чат?   -  person AndroidEnthusiast    schedule 15.01.2016
comment
Давайте продолжим обсуждение в чате.   -  person Christian Melchior    schedule 15.01.2016


Ответы (1)


Вместо сохранения данных в потоке пользовательского интерфейса я бы сделал это в фоновом режиме, используя следующий шаблон:

fetchItemsFromServer()
    .doOnNext(new Action1<ItemList>() {
        @Override
        public ItemList call(ItemList list) {
            // Save data on the background thread
            Realm realm = Realm.getDefaultInstance();
            realm.beginTransaction();
            realm.copyToRealmOrUpdate(list);
            realm.commitTransaction();
            realm.close();
        }
    })
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(new Action1<ItemList>() {
    @Override
    public void call(ItemList items) {
        displayItems(items);
    }
}
person Christian Melchior    schedule 15.01.2016
comment
Это означает, что вы, вероятно, получаете исключение откуда-то еще. Этот фрагмент кода гарантированно использует экземпляр Realm только в одном потоке. - person Christian Melchior; 18.01.2016
comment
Я потратил больше времени на изучение этого, вы правы. Я получал исключение из другого места, которое обращалось к сфере из пользовательского интерфейса. - person AndroidEnthusiast; 25.01.2016