Этот вопрос представляет собой следующий вопрос: Организуйте данные 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);
}
}
}
Сначала вы запрашиваете 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)
.
onCreate
и должен ждать обратных вызовов.
Я знаю, что вы сказали, что не рассматриваете возможность использования синхронного API, но я все же считаю, что стоит отметить, что ваша проблема будет решена так:
RealmResults<Photo> results = realm.where(ListPhoto.class).equalTo("id", id).findFirst()
.getList().where().findAll();
EDIT: Чтобы быть полностью информативным, я цитирую docs:
findFirstAsync
public E findFirstAsync()
Аналогично findFirst(), но выполняется асинхронно на рабочем потоке. Этот метод доступен только из потока Looper.
Возвращает: немедленно пустой объект RealmObject.
Попытка доступа к любому полю возвращаемого объекта перед его загрузкой будет вызывать исключение IllegalStateException.
Используйте RealmObject.isLoaded(), чтобы проверить, полностью ли загружен объект
или зарегистрировать прослушиватель
RealmObject.addChangeListener(io.realm.RealmChangeListener<E>)
, чтобы быть когда запрос завершен.Если RealmObject не был найден после запрос завершен, возвращаемый объект RealmObject будет иметь Значение RealmObject.isLoaded() установлено в true и значение RealmObject.isValid() установлено в ложь.
Итак, технически да, вам нужно сделать следующее:
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();
}
}
realm.where(ListPhoto.class).equalTo("id", id).findFirst().getList()
вы объяснить, как это будет отличаться от прямого использования списка следующим образом: realm.where(ListPhoto.class).equalTo("id", id).findFirst().getList()
Я имею в виду, если список уже существует Мне не нужен второй запрос, я могу напрямую использовать RealmList<Photo>
. Нет?
OrderedRealmCollection<T>
, но вы сказали, что хотите RealmResults<Photo>
, и это преобразует список в результаты. Но это просто делает ваш list
.where().findAll()
как view
, на самом деле ничего не стоит делать .where().findAll()
.
realm.where(ListPhoto.class).equalTo("id", id).findFirstAsync();
?RealmResults<Photo>
(или даже непосредственноRealmList
), который будет соответствоватьRealmList<Photo>
внутриListPhoto
. Я знаю, что могу сделать это синхронным звонком. Но я действительно лучше использую async.