2016-12-18 3 views
0

Я работаю с RxJava + Realm и хотел бы сделать что-то, что кажется довольно простой:Transform RealmResult в одном фоновом потоке с RxJava

Я хочу, чтобы загрузить все RealmObjects, которые соответствуют определенным критериям, преобразование каждого из RealmResult объекты, а затем уведомлять основной поток, когда эти преобразованные объекты готовы. Причина, по которой мне нужно преобразование в фоновом потоке, а также длительная работа, если в RealmResults имеется большое количество объектов

Проблема в том, что я могу загрузить объекты в фоновом режиме , но не может ничего сделать с каждым из объектов, все еще находясь в фоновом потоке. Я также пытаюсь сделать это в реактивной манере.

код до сих пор:

groupContactSubscription = realm.where(GroupContact.class) 
       .equalTo(MODEL_ID, mGroupId) 
       .findAllAsync() 
       .asObservable() 
       .filter(new Func1<RealmResults<GroupContact>, Boolean>() { 
        @Override 
        public Boolean call(RealmResults<GroupContact> groupContacts) { 
         return groupContacts.isLoaded(); 
        } 
       }) 
       .first() 
       .map(new Func1<RealmResults<GroupContact>, List<Contact>>() { 
        @Override 
        public List<Contact> call(RealmResults<GroupContact> groupContacts) { 
         List<Contact> contacts = new ArrayList<>(); 

         //Transform each GroupContact 
         for(int i=0; i<groupContacts.size(); ++i){ 
          contacts.add(transformGroupContact(groupContacts.get(0)) 
         } 
         return contacts; 
        } 
       }) 
       .observeOn(AndroidSchedulers.mainThread()) 
       .subscribe(new Action1<List<Contact>>() { 
        @Override 
        public void call(List<Contact> contacts) { 
         // Deal with transformed objects 
        } 
       }); 

Проблема в том, что это не происходит в фоновом потоке (она по-прежнему блокирует основной поток).

Я не совсем уверен, как это должно быть сделано чисто, может ли кто-нибудь указать мне в правильном направлении, что случилось с тем, что у меня уже есть? Я считаю, что транзакция Realm происходит асинхронно, а filter-> map также происходит на том же фоновом потоке. Ясно, что это не так.

Это моя попытка, используя RxJava поэтому, пожалуйста, будьте добры

+0

Вы считали * не * преобразование набора результатов и, таким образом, устранение необходимости считывать * каждый отдельный элемент набора результатов * из базы данных, а вместо этого вместо этого использовать возможности ленивой загрузки Realm? Просто интересуюсь. – EpicPandaForce

ответ

1
 groupContactSubscription = Observable.fromCallable(() -> { 
       try(Realm realm = Realm.getDefaultInstance()) { 
        RealmRefresh.refreshRealm(realm); // from http://stackoverflow.com/a/38839808/2413303 
        RealmResults<GroupContact> groupContacts = realm.where(GroupContact.class) 
                   .equalTo(MODEL_ID, mGroupId) 
                   .findAll(); 
        List<Contact> contacts = new ArrayList<>(); 
        //Transform each GroupContact 
        for(int i = 0; i < groupContacts.size(); ++i) { 
         contacts.add(transformGroupContact(groupContacts.get(i)); 
        } 
        return contacts;       
       } 
      }) 
      .subscribeOn(Schedulers.io()) 
      .observeOn(AndroidSchedulers.mainThread()) 
      .subscribe(new Action1<List<Contact>>() { 
       @Override 
       public void call(List<Contact> contacts) { 
        // Deal with transformed objects 
       } 
      }); 

Хотя это не автоматическое обновление, поэтому я немного туманными на этом, но я думаю, что это будет работать :

 groupContactSubscription = realm.where(GroupContacts.class).findAll().asObservable() 
     .observeOn(Schedulers.io()) 
     .switchMap(() -> 
      Observable.fromCallable(() -> { 
       try(Realm realm = Realm.getDefaultInstance()) { 
        RealmRefresh.refreshRealm(realm); // from http://stackoverflow.com/a/38839808/2413303 
        RealmResults<GroupContact> groupContacts = realm.where(GroupContact.class) 
                   .equalTo(MODEL_ID, mGroupId) 
                   .findAll(); 
        List<Contact> contacts = new ArrayList<>(); 
        //Transform each GroupContact 
        for(int i = 0; i < groupContacts.size(); ++i) { 
         contacts.add(transformGroupContact(groupContacts.get(i)); 
        } 
        return contacts;       
       } 
      }) 
      .subscribeOn(Schedulers.io()) 
      .observeOn(AndroidSchedulers.mainThread()) 
      .subscribe(new Action1<List<Contact>>() { 
       @Override 
       public void call(List<Contact> contacts) { 
        // Deal with transformed objects 
       } 
      }); 

Хотя с a proper Realm schema, вам даже не нужно будет делать такие преобразования (которые приводят к жадности оценки всей базы данных, беспересадочному крыло lazy-loading из окна), вы бы просто сделали

Subscription contacts = realm.where(Contact.class) 
             .equalTo("groupContact.modelId", mGroupId) 
             .findAllAsync() 
             .asObservable() 
             .filter(RealmResults::isLoaded) 
             .filter(RealmResults::isValid) 
             .subscribe(...); 

Или что-то в этом роде. Возможно, просто верните GroupContact как есть.

+0

Хм, казалось бы, я работал слепым и забыл о ленивой загрузке Realm из коробки ... Операция по преобразованию результата довольно быстрая (медленная, когда дело доходит до каждого RealmResult, хотя ..), и возможно, лучше всего преобразовать результат в адаптер адаптера recycler. Таким образом, я могу сделать некоторый уровень кэширования (возможно, кеш LRU с фиксированным размером) и загружать только данные, когда мне это нужно. Я думаю, что это имеет смысл, потому что, как вы предлагаете, кажется глупым загружать все данные с нетерпением и преобразовывать их ... – rosenthal

+0

Технически, если вы можете сделать это так, чтобы вы получили 'RealmResults ' в своем адаптере, тогда вы будете только трансформировать элементы, которые на самом деле отображаются на данный момент. Если вы используете ['RealmRecyclerViewAdapter'] (https://github.com/realm/realm-android-adapters), то вы можете вырезать RxJava для этого прецедента и просто дать' realm.where (Blah.class) ./ * ... */findAllAsync() 'к адаптеру, и он будет управлять загрузкой. – EpicPandaForce

+0

Спасибо, босс - это все имеет смысл. Примите ответ, потому что вы предоставили решение, которое сработало бы, но ваш первоначальный комментарий напомнил мне то, что я по ошибке забыл – rosenthal