检索结果的List包装

在BDFlow库中提供了FlowCursorListFlowQueryList两个容器类,可用于容纳检索结果。它们提供与List相同的方法使你能简单地将其用于BaseAdapter或其他List<? extends Model>可用的地方。

FlowCursorList

FlowCursorList是一个只读的用于缓存的容器,它包含的方法很类似与BaseAdapter比如getCount()getItem(position)方法(但并没有继承BaseAdapter和List)

对于我们需要在屏幕上显示大量数据但实际只需要载入显示部分的数据时,这个容器非常有用。它虽然像是CursorAdapter但并不继承任何Adapter类,但提供了与数据库数据检索、转换的方便的API接口。

这里是定义它的一些方式:

  • 使用任意的查询语句初始化它,像是FromStringQueryWhere

    // 第一个参数指定是否开启缓存
    new FlowCursorList<>(true, SQLite.select().from(TestModel.class)
    .where(TestModel1_Table.name.like("pasta%")));
    
    // 开启缓存并指定缓存大小(当缓存不可用时忽略)
    new FlowCursorList<>(1000, SQLite.select().from(TestModel.class)
    .where(TestModel1_Table.name.like("pasta%")));
    
  • 对特定类和列条件进行检索

    new FlowCursorList<>(true, TestModel.class, TestModel1_Table.name.like("pasta%"));
    
    new FlowCursorList<>(1000, TestModel.class, TestModel1_Table.name.like("pasta%"));
    

示例

  private class TestModelAdapter extends BaseAdapter {
    private FlowCursorList<TestModel1> mFlowCursorList;

    public TestModelAdapter() {

    // retrieve and cache rows that have a name like pasta%
      mFlowCursorList = new FlowCursorList<>(true, TestModel.class,
            TestModel1_Table.name.like("pasta%"));
    }

    @Override
    public int getCount() {
      return mFlowCursorList.getCount();
    }

    @Override
    public TestModel1 getItem(int position) {
      return mFlowCursorList.getItem(position);
    }

    @Override
    public long getItemId(int position) {
      return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
      // Implement here
    }
  }

自定义缓存

可以通过重写getBackingCache()方法来替换默认的LruCache缓存方式:

FlowCursorList<TestModel> list = new FlowCursorList<TestModel>(true, someWhere) {

    @Override
    protected ModelCache<TestModel, ?> getBackingCache() {
      return new SparseArrayBasedCache();
    }

}

FlowQueryList

FlowQueryList

  1. 实现了java的List接口
  2. 所有对表的修改都是实时的
  3. 默认情况下所有的修改都是即时的
  4. 如果你不希望这些修改操作在主线程中进行,请设置flowTableList.setTransact(true)
  5. Internally its backed by a FlowCursorList to include all of it's existing functionality.

好的实践

  • 不要在循环中进行大量的单一操作,因为每个操作都会调用refresh()方法刷新数据库。推荐的做法是使用事务包裹这些操作:

    FlowQueryList<TableModel> flowQueryList = ...;
    
    // DON'T
    for (int i = 0; i < 50; i++) {
        TableModel object = anotherList.get(i);
        flowQueryList.remove(object);
    }
    
    // better
    flowQueryList.beginTransaction();
    for (int i = 0; i < 50; i++) {
        TableModel object = anotherList.get(i);
        flowQueryList.remove(object);
    }
    flowQueryList.endTransactionAndNotify();
    
    // DO
    flowQueryList.removeAll(anotherList);
    
  • 在其他地方对数据进行了修改后,FlowQueryList内的数据会不一致,有两种方式刷新数据:

    1. 调用refresh()方法手动刷新数据
    2. 开启自动刷新:
      flowQueryList.enableSelfRefreshes(context);
      
  • 如果你进行了大量的更改同时对这些事件都注册了监听,好的方式是使用endTransactionAndNotify()方法将通知在最后统一发送。

    flowQueryList.beginTransaction();
    
    // perform model changes!!
    
    // calls any listeners associated with it (including the listener we registered earlier)
    // refreshes the list here (if registered)
    flowQueryList.endTransactionAndNotify();
    

示例

  FlowQueryList<TestModel1> flowQueryList = new FlowQueryList<TestModel1>(TestModel1.class);

  flowQueryList.beginTransaction();

  // Deletes from the table and returns the item
  TestModel1 model1 = flowQueryList.remove(0);

  // Saves the item back into the DB, updates if it already exists
  flowQueryList.add(model1);

  // Updates the item in the DB
  flowQueryList.set(model1);

  // Clears the whole table
  flowQueryList.clear();

  flowQueryList.endTransactionAndNotify();