2016-01-24 30 views
3

我在我的開源Linux命令庫項目中用領域替換了sqlite。到目前爲止,一切都很順利,但現在我面臨一個問題。複雜的排序搜索領域,多個RealmResults聯合

我正在使用RealmBaseAdapter在搜索界面中顯示ListView中的所有命令。對於搜索領域狙擊以下命令的結果是這樣的:

查詢: 測試

結果:

  • L2 測試
  • RC 測試
  • 測試
  • 測試 PARM

    RealmResults<Command> commands = mRealm.where(Command.class).contains("name", query).findAll(); 
    mAdapter.updateRealmResults(commands); 
    

在舊源碼邏輯的順序是這樣的:

結果:

  • 測試
  • 試驗 PARM
  • L2 測試
  • RC 測試

return getReadableDatabase().rawQuery("Select * from " + CommandsDBTableModel.TABLE_COMMANDS + " WHERE " + CommandsDBTableModel.COL_NAME + " LIKE '%" + query + "%' " + "ORDER BY " + CommandsDBTableModel.COL_NAME + " = '" + query + "' DESC," + CommandsDBTableModel.COL_NAME + " LIKE '" + query + "%' DESC", null);

是否有可能與境界去實現它呢? 這裏是項目鏈接https://github.com/SimonSchubert/LinuxCommandBibliotheca

+1

我一起從兩個查詢,一個startsWith()和一個境界結果創建一個自定義適配器件本身「包含但不以「開始。 – EpicPandaForce

+1

謝謝,它的工作。 –

回答

6

謝謝你們,你們都幫我解決了這個問題。@Mateusz Herych @EpicPandaForce

這裏是定製適配器:

public abstract class RealmMultiAdapter<T extends RealmObject> extends BaseAdapter { 

    private final RealmChangeListener<T> realmChangeListener = new RealmChangeListener<T>() { 
     @Override 
     public void onChange(RealmResults<T> t) { 
      notifyDataSetChanged(); 
     } 
    }; 

    protected LayoutInflater inflater; 
    protected List<RealmResults<T>> realmResults; 
    protected Context context; 

    public RealmMultiAdapter(Context context, List<RealmResults<T>> realmResults, boolean automaticUpdate) { 
     if (context == null) { 
      throw new IllegalArgumentException("Context cannot be null"); 
     } 
     this.context = context; 
     this.realmResults = realmResults; 
     this.inflater = LayoutInflater.from(context); 
     for(RealmResults<T> results : realmResults) { 
      results.addChangeListener(realmChangeListener); 
     } 
    } 

    /** 
    * Returns how many items are in the data set. 
    * 
    * @return count of items. 
    */ 
    @Override 
    public int getCount() { 
     if (realmResults == null) { 
      return 0; 
     } 
     int count = 0; 
     for(RealmResults<T> realmResult : realmResults) { 
      count += realmResult.size(); 
     } 
     return count; 
    } 

    /** 
    * Returns the item associated with the specified position. 
    * 
    * @param i index of item whose data we want. 
    * @return the item at the specified position. 
    */ 
    @Override 
    public T getItem(int i) { 
     if (realmResults == null || realmResults.size()==0) { 
      return null; 
     } 
     int count = 0; 
     for(RealmResults<T> realmResult : realmResults) { 
      if(i<realmResult.size()+count) { 
       return realmResult.get(i-count); 
      } 
      count += realmResult.size(); 
     } 
     return null; 
    } 

    /** 
    * Returns the current ID for an item. Note that item IDs are not stable so you cannot rely on the item ID being the 
    * same after {@link #notifyDataSetChanged()} or {@link #updateRealmResults(List<RealmResults<T>>)} has been called. 
    * 
    * @param i index of item in the adapter. 
    * @return current item ID. 
    */ 
    @Override 
    public long getItemId(int i) { 
     // TODO: find better solution once we have unique IDs 
     return i; 
    } 

    /** 
    * Updates the RealmResults associated to the Adapter. Useful when the query has been changed. 
    * If the query does not change you might consider using the automaticUpdate feature. 
    * 
    * @param queryResults the new RealmResults coming from the new query. 
    */ 
    public void updateRealmResults(List<RealmResults<T>> queryResults) { 
     for(RealmResults<T> results : realmResults) { 
      if(results.isValid()) {    
       results.removeChangeListener(realmChangeListener); 
      } 
     } 
     this.realmResults = queryResults; 
     for(RealmResults<T> results : realmResults) { 
      results.addChangeListener(realmChangeListener); 
     } 
     notifyDataSetChanged(); 
    } 
} 

基本上我取代單RealmResult與RealmResults的列表,並修改爲getItem()和getCount將()方法。

// before 
    protected RealmResults<T> realmResults; 
    // after 
    protected List<RealmResults<T>> realmResults; 

這就是我如何更新搜索

List<RealmResults<Command>> results = new ArrayList<>(); 
    results.add(mRealm.where(Command.class).equalTo("name", query).findAll()); 
    results.add(mRealm.where(Command.class).beginsWith("name", query).notEqualTo("name", query).findAll()); 
    results.add(mRealm.where(Command.class).contains("name", query).not().beginsWith("name", query).notEqualTo("name", query).findAll()); 

    mAdapter.updateRealmResults(results); 
+1

如果你還沒有,如果你的'name'屬性不是命令的主鍵,那麼一定要添加'@ Index'註釋來大大提高查詢性能。 – EpicPandaForce

+0

不,我沒有,@Index name屬性對我來說是有意義的。我會這樣做,謝謝。 –

+0

@SimonSchubert你能否給我提供擴展RealmMultiAdapter的適配器片段。我想知道你如何使用realmresult列表來查看你的視圖。 – swati

1

不確定是否沒有更好/更高性能的方式,但你可以嘗試做3個不同的查詢,然後連接他們的結果。

List<Command> commands = new ArrayList<>(); 

    commands.addAll(realm.where(Command.class) 
      .equalTo("name", query) 
      .findAll()); 

    commands.addAll(realm.where(Command.class) 
      .beginsWith("name", query) 
      .notEqualTo("name", query) 
      .findAll()); 

    commands.addAll(realm.where(Command.class) 
      .contains("name", query) 
      .not().beginsWith("name", query) 
      .findAll()); 

這顯然涉及到從RealmBaseAdapter改變你Adapter實現的東西更正規。請記住,雖然Realm對象位於常規列表中,但它們仍與您的Realm數據庫保持連接,因此在ListView顯示數據時無法關閉領域實例。

更新:正如@EpicPandaForce在評論中指出的那樣,該解決方案在Realm的自動配置中不能很好地工作。可能會出現某些命令被刪除/已更改的名稱,在此情況下,您的適配器不會反映這些名稱。確保先複製對象,並在領域結果上設置更改偵聽器。

+0

我不認爲這將適合領域的自動化。 – EpicPandaForce

+0

@EpicPandaForce連接多個RealmResults的可靠方法? –

+0

好主意,我沒想過。問題是Command數據庫有~2400行,我想堅持RealmBaseAdapter。由於性能和記憶的原因。 –