2017-08-11 63 views
1

所以,我有一个使用realm.io的Android应用程序。我必须像这样异步运行查询:在Android中链接领域查询的最佳做法是什么?

public static void getProductsByCategoryId(Realm realm, 
    String categoryId, 
    OrderedRealmCollectionChangeListener<RealmResults<Product>> callback) { 

    RealmResults<Product> result = realm.where(Product.class) 
      .equalTo(CATEGORY, categoryId) 
      .findAllAsync(); 
    result.addChangeListener(callback); 
} 

回调将处理此响应,但随后我需要按顺序运行另一个查询。所以,你将有queryA => process response => queryB => process response。所以,回调可能有这样的代码

..... 
getProductsByCategoryId(app.getRealmInstance(), "ABC123", firstCallback); 
..... 
private OrderedRealmCollectionChangeListener<RealmResults<Product>> firstCallback = new OrderedRealmCollectionChangeListener<RealmResults<Product>>() { 

     @Override 
     public void onChange(RealmResults<Product> realmProducts, OrderedCollectionChangeSet changeSet) { 

       mProdList.addAll(mRealm.copyFromRealm(realmProducts)); 

       // get more product info (2nd call) 
       MainApplication.getMoreProductInfo(mRealm, mCatId, false, secondCallback); 
     } 
    }; 

目前,我的理解是,你会在queryA的回调中运行queryB?看看应用程序的要求,我最终会得到3或4个查询链。这是一个合适的方法,还是有我应该使用的特定模式?我还没有在Realm文档中找到任何指导。

+0

'这是一个合适的方法不,这种方法大约有三件事是错误的。尽管在后台如果需要4次查询才能获取所有数据,最有可能是设计得不好的架构。 – EpicPandaForce

+0

那么,猜测*为什么你首先需要4个随后的查询*是不可能的。通常为了最佳使用,你不应该从Realm **复制的RealmResults应该来自单个查询,它将以正确的顺序(排序)获得包含所需信息的对象, 。取决于是否有可能*没有*使用4个查询是它自己的问题,并且在从Realm复制时,这可能仅仅是同一个BG线程上的4个同步查询。这样你的RealmResults不会被GC *有时*杀死。 – EpicPandaForce

+0

在过去的SQL数据库日子里,您可以使用内部或外部联接来克服原始数据库设计中未考虑的异常查询,或者您无权创建视图。这种情况今天仍然发生。我用来克服这种情况的一种方法是链接查询。我正在寻找更好的方法。如果你不知道如何解决它,那么它并不一定意味着它不是一个合理的问题。也许这超出了你的技能水平,在这种情况下,把它留给其他人。你已经提出了一个答案,但如果它是一个评论我不能标记 – giulio

回答

1

它通常是不好的架构设计的迹象,如果你需要做多个查询,以便检索结果集,因为领域工作的方式是,如果你可以用一个查询定义查询结果(和你不不使用realm.copyFromRealm(),你通常不需要使用),那么它的元素和结果本身都是惰性加载的。

如果你不能做到这一点,那么即使是这样,通常你可能不应该链find*Async电话,因为你不存储为一个字段变量任何 RealmResults具有的GC不被消耗的机会,而其当isLoaded()为真时(因为所述RealmResults不再存在),将不会调用更改侦听器。

所以,你似乎真的想要做的仅仅是在后台线程上执行多个查询,然后复制结果返回给主线程,在这种情况下,刚刚这个样子

Executor executor = Executors.newSingleThreadedPool(); // or some other pool 
Handler handler = new Handler(Looper.getMainLooper()); 

public void getQueryResults(DataLoadedCallback callback) { 
    executor.execute(() -> { 
     try(Realm realm = Realm.getDefaultInstance()) { 
      realm.refresh(); // <-- might not be necessary 
      RealmResults<XYZ> results1 = realm.where(XYZ.class)./*...*/.findAll(); 
      RealmResults<ZXY> results2 = realm.where(ZXY.class)./*...*/.findAll(); 
      RealmResults<YZX> results3 = realm.where(YZX.class)./*...*/.findAll(); 
      List<Something> someList = new LinkedList<>(); 
      for/*do magic transform things*/ 
       someList.add(blah /* blah is not a managed RealmObject */); 
      } 
      handler.post(() -> { 
       callback.onDataLoaded(Collections.unmodifiableList(new ArrayList<>(someList))); 
      }); 
     } 
    }); 
} 
+0

是的,模式设计并不是最佳状态,但我正在研究一个不够灵活的大型项目来优化模式。所以,我不得不采取这个不寻常的步骤来运行多个查询。感谢您的替代方法..我试试这个..顺便说一句,有一个问题,使用标准的AsyncTask来代替处理程序,并使用“doInBackground”处理它,并在onPostExecute中显示结果? – giulio

+1

我对AsyncTask有一般的不信任,但理论上它应该工作。 – EpicPandaForce

0

在回调中链接查询是好的,“应该只是工作”,但如果你能表达你想要的尽可能少的查询,效率会更高。

理想情况下,我们应该有一个足够强大的查询语言来表达您在一个查询中需要的所有内容。我们还没有完全实现,但我们非常有兴趣了解更多关于您具体要求的信息。

此外,您不清楚为什么您在发布的方法中使用copyFromRealm,但在理想的情况下应该不需要。

+0

AFAIK他添加了更改侦听器的异步查询可以被GC使用,并且他的链将停止,考虑到每个将在“稍后”执行,并且只有在每个更改侦听器也在isLoaded()之后被调用时才会有效。 “是真的,不是吗? – EpicPandaForce

+0

这取决于如何存储辅助侦听器,我无法从代码中知道“MainApplication.getMoreProductInfo”的作用。但是,是的,如果你将它们链接起来,冒险让它们变得相当容易。 –

+0

@ChristianMelchior感谢伸出援手。 copyFromRealm仅用于将结果转换为ArrayList,因为该内容在应用程序中以其他方式使用。这似乎是一种有用的实用方法来转换结果。但是它不应该分散我的问题的前提,那就是如何可靠地在Android中使用Realm执行链式查询。背景:这是一个来自复杂数据模型的目录应用程序,用于构建其内容跨越多个表格的产品页面。请让你自己的假设来提出你的首选方法。道歉,如果这有点太广泛。 – giulio

相关问题