Запросить данные области, содержащиеся в другом объекте

Этот вопрос является дополнительным вопросом от: Организация данных Android Realm в списках

Из-за данных, возвращаемых API, который мы используем, сделать запрос к базе данных области практически невозможно. Вместо этого я упаковываю свои заказанные данные в RealmList и добавив @PrimaryKey public String id; к этому.

Таким образом, наши данные области выглядят так:

public class ListPhoto extends RealmObject {
   @PrimaryKey public String id;
   public RealmList<Photo> list; // Photo contains String/int/boolean
}

что облегчает запись и чтение из БД Realm, просто используя конечную точку API в качестве id,

Таким образом, типичный запрос выглядит так:

realm.where(ListPhoto.class).equalTo("id", id).findFirstAsync();

Это создает немного накладных listening/subscribing к данным, потому что теперь мне нужно проверить listUser.isLoaded() использование ListUser в addChangeListener/removeChangeListener а также ListUser.list как фактические данные на моем адаптере.

Итак, мой вопрос:

Есть ли способ, которым я могу запросить эту область, чтобы получить RealmResults<Photo>, Таким образом, я мог бы легко использовать эти данные в RealmRecyclerViewAdapter и использовать слушателей прямо на нем.

Изменить: чтобы уточнить, я хотел бы что-то вроде следующего (я знаю, что это не компилируется, это просто псевдокод, что я хотел бы достичь).

realm
 .where(ListPhoto.class)
      .equalTo("id", id)
      .findFirstAsync()  // get a results of that photo list
 .where(Photo.class)
      .getField("list")
      .findAllAsync(); // get the field "list" into a `RealmResults<Photo>`

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

public abstract class RealmAdapter
                     <T extends RealmModel, 
                      VH extends RecyclerView.ViewHolder> 
            extends RealmRecyclerViewAdapter<T, VH>
            implements RealmChangeListener<RealmModel> {

   public RealmAdapter(Context context, OrderedRealmCollection data, RealmObject realmObject) {
      super(context, data, true);
      if (data == null) {
         realmObject.addChangeListener(this);
      }
   }

   @Override public void onChange(RealmModel element) {

      RealmList list = null;
      try {
         // accessing the `getter` from the generated class
         // because it can be list of Photo, User, Album, Comment, etc
         // but the field name will always be `list` so the generated will always be realmGet$list
         list = (RealmList) element.getClass().getMethod("realmGet$list").invoke(element);
      } catch (Exception e) {
         e.printStackTrace();
      }

      if (list != null) {
         ((RealmObject) element).removeChangeListener(this);
         updateData(list);
      }
   }
}

2 ответа

Решение

Сначала вы запрашиваете ListPhoto, потому что это асинхронно, вы должны зарегистрировать прослушиватель для результатов. Затем в этом слушателе вы можете запросить результат, чтобы получить RealmResult.

Что-то вроде этого

final ListPhoto listPhoto = realm.where(ListPhoto.class).equalTo("id", id).findFirstAsync();
listPhoto.addChangeListener(new RealmChangeListener<RealmModel>() {
    @Override
    public void onChange(RealmModel element) {
        RealmResults<Photo> photos = listPhoto.getList().where().findAll();
        // do stuff with your photo results here.


        // unregister the listener.
        listPhoto.removeChangeListeners();
    }
});

Обратите внимание, что вы можете запросить RealmList. Вот почему мы можем позвонить listPhoto.getList().where(), where() просто означает "вернуть все".

Я не могу проверить это, потому что у меня нет вашего кода. Возможно, вам придется разыграть element с ((ListPhoto) element),

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

RealmResults<Photo> results = realm.where(ListPhoto.class).equalTo("id", id).findFirst()
                           .getList().where().findAll();

РЕДАКТИРОВАТЬ: Чтобы быть полностью информативным, я цитирую документы:

findFirstAsync

public E findFirstAsync ()

Аналогичен findFirst(), но работает асинхронно в рабочем потоке. Этот метод доступен только из потока Looper.

Возвращает: сразу пустой RealmObject.

Попытка получить доступ к любому полю возвращаемого объекта до его загрузки вызовет исключение IllegalStateException.

Используйте RealmObject.isLoaded(), чтобы проверить, полностью ли загружен объект

или зарегистрировать слушателя RealmObject.addChangeListener(io.realm.RealmChangeListener<E>) получать уведомление, когда запрос завершается.

Если RealmObject не был найден после завершения запроса, возвращенный RealmObject будет иметь для RealmObject.isLoaded() значение true и для RealmObject.isValid() значение false.

Технически, да, вам нужно сделать следующее:

private OrderedRealmCollection<Photo> photos = null;
//...

final ListPhoto listPhoto = realm.where(ListPhoto.class).equalTo("id", id).findFirstAsync();
listPhoto.addChangeListener(new RealmChangeListener<ListPhoto>() {
    @Override
    public void onChange(ListPhoto element) {
        if(element.isValid()) {
            realmRecyclerViewAdapter.updateData(element.list);
        }
        listPhoto.removeChangeListeners();
    }
}
Другие вопросы по тегам