用于领域搜索的复杂排序,多个RealmResults的并集

时间:2016-01-24 11:17:09

标签: android sqlite realm

我在我的开源Linux Command Library项目中用realm替换了sqlite。到目前为止,一切都很顺利,但现在我遇到了问题。

我使用RealmBaseAdapter通过搜索界面显示ListView中的所有命令。对于搜索,下面的区域命令结果如下:

查询: 的测试

结果:

  • l2 测试
  • RC的测试
  • 测试
  • 测试的parm

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

使用旧的sqlite逻辑,顺序是这样的:

结果:

  • 测试
  • 测试的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

的链接

2 个答案:

答案 0 :(得分: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();
    }
}

基本上我用RealmResults列表替换了单个RealmResult,并修改了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 :(得分:1)

不确定是否有更好/更高效的方式,但您可以尝试制作3个不同的查询,然后连接其结果。

#app/assets/stylesheets/application.css
@media screen and (max-width: 767px) {
   .big   { display: none; }
   .small { display: block; }
}

#app/view
<%= content_tag :div, class: "big" do %>
   <table>
     <tr>
         <th>Title</th>
         <th>Genre</th>
         <th>Description</th>
      </tr>
      <tr>
         <td><%= @book.title %></td>
         <td><%= @book.genre %></td>
         <td><%= @book.desc %></td>
       </tr>
    </table>
<% end %>
<%= content_tag :div, class: "small" do %>
   Title: <br>
     <%= @book.title %><br>
   Genre: <br>
     <%= @book.genre %>
   Description:
     <%= @book.desc %>       
<% end %>

这显然涉及将 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()); 实施从Adapter更改为更常规的内容。请记住,虽然您的Realm对象位于常规列表中,但它们仍与您的RealmBaseAdapter数据库保持连接,因此您在ListView显示数据时无法关闭您的领域实例。

更新:正如@EpicPandaForce在评论中指出的那样,这个解决方案并不适用于Realm的自动更新。可能会出现某些命令被删除/已更改名称,在这种情况下,这不会被适配器反映出来。确保首先复制对象并在领域结果上设置更改侦听器。