Query realm data contained on other object

混江龙づ霸主 提交于 2019-12-23 01:06:11

问题


This question is a follow-up question from: Organize Android Realm data in lists

Due to the data returned by the API we use, it's slightly impossible to do an actual query on the realm database. Instead I'm wrapping my ordered data in a RealmList and adding a @PrimaryKey public String id; to it.

So our realm data looks like:

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

which makes easy to write to and read from the Realm DB by simply using the API endpoint as the id.

So a typical query on it looks like:

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

This creates a slightly overhead of listening/subscribing to data because now I need to check listUser.isLoaded() use ListUser to addChangeListener/removeChangeListener and ListUser.list as an actual data on my adapter.

So my question is:

Is there a way I can query this realm to receive a RealmResults<Photo>. That way I could easily use this data in RealmRecyclerViewAdapter and use listeners directly on it.

Edit: to further clarify, I would like something like the following (I know this doesn't compile, it's just a pseudo-code on what I would like to achieve).

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>`

edit final code: considering it's not possible ATM to do it directly on queries, my final solution was to simply have an adapter that checks data and subscribe if needed. Code below:

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);
      }
   }
}

回答1:


First you query the ListPhoto, because it's async you have to register a listener for the results. Then in that listener you can query the result to get a RealmResult.

Something like this

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();
    }
});

Note that you can actually query a RealmList. That's why we can call listPhoto.getList().where(). The where() just means "return all".

I cannot test it because I don't have your code. You may need to cast the element with ((ListPhoto) element).




回答2:


I know you said you're not considering the option of using the synchronous API, but I still think it's worth noting that your problem would be solved like so:

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

EDIT: To be completely informative though, I cite the docs:

findFirstAsync

public E findFirstAsync()

Similar to findFirst() but runs asynchronously on a worker thread This method is only available from a Looper thread.

Returns: immediately an empty RealmObject.

Trying to access any field on the returned object before it is loaded will throw an IllegalStateException.

Use RealmObject.isLoaded() to check if the object is fully loaded

or register a listener RealmObject.addChangeListener(io.realm.RealmChangeListener<E>) to be notified when the query completes.

If no RealmObject was found after the query completed, the returned RealmObject will have RealmObject.isLoaded() set to true and RealmObject.isValid() set to false.

So technically yes, you need to do the following:

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();
    }
}


来源:https://stackoverflow.com/questions/38220180/query-realm-data-contained-on-other-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!