Запросить данные области, содержащиеся в другом объекте
Этот вопрос является дополнительным вопросом от: Организация данных 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();
}
}