我们有时在处理数据时可能用Cursor比较方便。但我们如何自己创造一个Cursor呢?

这时我们可以用Android为我们提供的MatrixCursor类,自己创造一个Cursor。

下面通过一个事例来分析,如何创造一个Cursor作为SimpleCursorAdapter的数据来源。

##1、Activity布局

      android:textSize="24sp"        android:gravity="center_horizontal"        />            

##2、ListView中的数据布局

<?xml version="1.0" encoding="utf-8"?>        

##3、模拟从服务器获取数据

public class MyDataBase {private static int count = 0;public static String[]Column = null;public static String[] getColumn(){if(null == Column){return new String[]{"姓名","班级","学号"};}return Column;}public static Object[] getColumnData(){count++;return new Object[]{new Integer(count),"zhangsan"+count,"jisuanji"+count,"201210"+count};}}

##4、Activity

public class MainActivity extends Activity {private ListView listView;private SimpleCursorAdapter sca;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);listView = (ListView) this.findViewById(R.id.listView);Cursor cursor = getCursor();String[] from = {"姓名","班级","学号"};int[] to = {R.id.name,R.id.banji,R.id.studentID};sca = new SimpleCursorAdapter(MainActivity.this, R.layout.adapter_view, cursor, from, to, 0);listView.setAdapter(sca);}private Cursor getCursor() {String[] columnNames = new String[4];int i = 0;columnNames[i] = "_id";for(String columnName : MyDataBase.getColumn()){columnNames[++i] = columnName;}MatrixCursor cursor = new MatrixCursor(columnNames);for(int j = 0; j<10; j++){cursor.addRow(MyDataBase.getColumnData());}return cursor;}}

##5、运行结果

Android中如何自己创造一个Cursor及MatrixCursor源码分析_第1张图片

##6、MatrixCursor源码分析

其实创造一个Cursor很简单!!!我们现在需要去查看源码分析下,android工程师的大牛们是如何实现MatrixCursor的。

/** * A mutable cursor implementation backed by an array of {@code Object}s. Use * {@link #newRow()} to add rows. Automatically expands internal capacity * as needed. */public class MatrixCursor extends AbstractCursor {    private final String[] columnNames;    private Object[] data;    private int rowCount = 0;    private final int columnCount;    /**     * Constructs a new cursor with the given initial capacity.     *     * @param columnNames names of the columns, the ordering of which     *  determines column ordering elsewhere in this cursor     * @param initialCapacity in rows     */    public MatrixCursor(String[] columnNames, int initialCapacity) {        this.columnNames = columnNames;        this.columnCount = columnNames.length;        if (initialCapacity < 1) {            initialCapacity = 1;        }        this.data = new Object[columnCount * initialCapacity];    }    /**     * Constructs a new cursor.     *     * @param columnNames names of the columns, the ordering of which     *  determines column ordering elsewhere in this cursor     */    public MatrixCursor(String[] columnNames) {        this(columnNames, 16);    }    /**     * Gets value at the given column for the current row.     */    private Object get(int column) {        if (column < 0 || column >= columnCount) {            throw new CursorIndexOutOfBoundsException("Requested column: "                    + column + ", # of columns: " +  columnCount);        }        if (mPos < 0) {            throw new CursorIndexOutOfBoundsException("Before first row.");        }        if (mPos >= rowCount) {            throw new CursorIndexOutOfBoundsException("After last row.");        }        return data[mPos * columnCount + column];    }    /**     * Adds a new row to the end and returns a builder for that row. Not safe     * for concurrent use.     *     * @return builder which can be used to set the column values for the new     *  row     */    public RowBuilder newRow() {        rowCount++;        int endIndex = rowCount * columnCount;        ensureCapacity(endIndex);        int start = endIndex - columnCount;        return new RowBuilder(start, endIndex);    }    /**     * Adds a new row to the end with the given column values. Not safe     * for concurrent use.     *     * @throws IllegalArgumentException if {@code columnValues.length !=     *  columnNames.length}     * @param columnValues in the same order as the the column names specified     *  at cursor construction time     */    public void addRow(Object[] columnValues) {        if (columnValues.length != columnCount) {            throw new IllegalArgumentException("columnNames.length = "                    + columnCount + ", columnValues.length = "                    + columnValues.length);        }        int start = rowCount++ * columnCount;        ensureCapacity(start + columnCount);        System.arraycopy(columnValues, 0, data, start, columnCount);    }    /**     * Adds a new row to the end with the given column values. Not safe     * for concurrent use.     *     * @throws IllegalArgumentException if {@code columnValues.size() !=     *  columnNames.length}     * @param columnValues in the same order as the the column names specified     *  at cursor construction time     */    public void addRow(Iterable<?> columnValues) {        int start = rowCount * columnCount;        int end = start + columnCount;        ensureCapacity(end);        if (columnValues instanceof ArrayList<?>) {            addRow((ArrayList<?>) columnValues, start);            return;        }        int current = start;        Object[] localData = data;        for (Object columnValue : columnValues) {            if (current == end) {                // TODO: null out row?                throw new IllegalArgumentException(                        "columnValues.size() > columnNames.length");            }            localData[current++] = columnValue;        }        if (current != end) {            // TODO: null out row?            throw new IllegalArgumentException(                    "columnValues.size() < columnNames.length");        }        // Increase row count here in case we encounter an exception.        rowCount++;    }    /** Optimization for {@link ArrayList}. */    private void addRow(ArrayList<?> columnValues, int start) {        int size = columnValues.size();        if (size != columnCount) {            throw new IllegalArgumentException("columnNames.length = "                    + columnCount + ", columnValues.size() = " + size);        }        rowCount++;        Object[] localData = data;        for (int i = 0; i < size; i++) {            localData[start + i] = columnValues.get(i);        }    }    /** Ensures that this cursor has enough capacity. */    private void ensureCapacity(int size) {        if (size > data.length) {            Object[] oldData = this.data;            int newSize = data.length * 2;            if (newSize < size) {                newSize = size;            }            this.data = new Object[newSize];            System.arraycopy(oldData, 0, this.data, 0, oldData.length);        }    }    /**     * Builds a row, starting from the left-most column and adding one column     * value at a time. Follows the same ordering as the column names specified     * at cursor construction time.     */    public class RowBuilder {        private int index;        private final int endIndex;        RowBuilder(int index, int endIndex) {            this.index = index;            this.endIndex = endIndex;        }        /**         * Sets the next column value in this row.         *         * @throws CursorIndexOutOfBoundsException if you try to add too many         *  values         * @return this builder to support chaining         */        public RowBuilder add(Object columnValue) {            if (index == endIndex) {                throw new CursorIndexOutOfBoundsException(                        "No more columns left.");            }            data[index++] = columnValue;            return this;        }    }    // AbstractCursor implementation.    @Override    public int getCount() {        return rowCount;    }    @Override    public String[] getColumnNames() {        return columnNames;    }    @Override    public String getString(int column) {        Object value = get(column);        if (value == null) return null;        return value.toString();    }    @Override    public short getShort(int column) {        Object value = get(column);        if (value == null) return 0;        if (value instanceof Number) return ((Number) value).shortValue();        return Short.parseShort(value.toString());    }    @Override    public int getInt(int column) {        Object value = get(column);        if (value == null) return 0;        if (value instanceof Number) return ((Number) value).intValue();        return Integer.parseInt(value.toString());    }    @Override    public long getLong(int column) {        Object value = get(column);        if (value == null) return 0;        if (value instanceof Number) return ((Number) value).longValue();        return Long.parseLong(value.toString());    }    @Override    public float getFloat(int column) {        Object value = get(column);        if (value == null) return 0.0f;        if (value instanceof Number) return ((Number) value).floatValue();        return Float.parseFloat(value.toString());    }    @Override    public double getDouble(int column) {        Object value = get(column);        if (value == null) return 0.0d;        if (value instanceof Number) return ((Number) value).doubleValue();        return Double.parseDouble(value.toString());    }    @Override    public byte[] getBlob(int column) {        Object value = get(column);        return (byte[]) value;    }    @Override    public int getType(int column) {        return DatabaseUtils.getTypeOfObject(get(column));    }    @Override    public boolean isNull(int column) {        return get(column) == null;    }}

通过分析我们得知:
1:Android大牛们,通过在MatrixCursor中封装一个Object[]数组保存我们每一列的值;通过一个常引用String[] columnNames来保存我们的列名。所以一旦我们的MatrixCursor对象建立,它的列名就不可改变。我们以后的数据存放都要依据我们的列名。
2:MatrixCursor通过 int rowCount = 0 来记录行数、private final int columnCount 记录列数。通过这两个数我们可以很容易的知道每一行数据在Object[]数组的区间。
3:MatrixCursor通过实现AbstractCursor中的抽象方法;当我们获取数据时调用MatrixCursor中复写的方法,来获取指定的行列值。

获取值最重要的方法是:

private Object get(int column) {        if (column < 0 || column >= columnCount) {            throw new CursorIndexOutOfBoundsException("Requested column: "                    + column + ", # of columns: " +  columnCount);        }        if (mPos < 0) {            throw new CursorIndexOutOfBoundsException("Before first row.");        }        if (mPos >= rowCount) {            throw new CursorIndexOutOfBoundsException("After last row.");        }        return data[mPos * columnCount + column];    }

无非就是两个值:mPos、column
mPos:代表了我们当前的要访问的行
column:代表我们当前要访问的列

###MatrixCursor内部类:RowBuilder

RowBuilder作用就是用来给MatrixCursor添加Row数据的,不过我们经常通过MatrixCursor.addRow()实现。就像AlertDialog.Builder一样,我们既可以通过AlertDialog.Builder来构建一个对话框,也可以通过AlertDialg直接来实现。

更多相关文章

  1. 【iOS-Android开发对比】之 数据存储
  2. (一)Android数据结构学习之链表
  3. Android中sqlite数据库的简单使用
  4. flutter与android混合开发一:Android原生项目创建flutter模块、An
  5. Android学习札记13:为什么更推荐使用Parcelable来在Activity间传

随机推荐

  1. Android 自定义AlertDialog
  2. android开发问题总结
  3. Android 中延迟执行的小结
  4. android动态申请拍照获取照片权限
  5. 徽章系列1: Top 30 android 开源项目徽章
  6. Android中用Toast.cancel()方法优化toast
  7. Android之-android-support-v4.jar的混淆
  8. Java Android 32位16位 MD5加密
  9. Android 三角标签控件、角标(AvatarLabelV
  10. 配置OpenCV for Android