android基礎知識08:android MatrixCursor源碼解析

來源:互聯網
上載者:User

        在上一篇文章中,我們對content provider基礎進行了詳細的介紹。該文中介紹的content provider都是基於sqlite的,但實際上content provider是可以基於其他儲存格式的。本文將開始介紹基於xml的content provider。
        第一步,我們先介紹一個重要的部分Cursor。基於xml的content provider所使用的Cursor與基於sqlite的是不同的。基於xml的Cursor需要繼承MatrixCursor類。本文先介紹MatrixCursor類。
       MatrixCursor類位於android.database包中。其中定義了四個變數,用來儲存相關的值,其介紹如下:
private final String[] columnNames; 存放列名
private Object[] data;                      
存放資料值。這裡,我通常認為應該用一個表(二維數組來存放資料值),但實際上卻是用一個一維數組來類比二維數組。所以對於一個二維數組:

其存放在data中的格式為

private int rowCount = 0;

MatrixCursor中存放的資料行數。因此很容易理解data數組的長度必須大於等於(columnCount*rowCount );

private final int columnCount;

列數=columnNames長度

        其建構函式為:

    /**     * 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);    }

       其中的initialCapacity,就是指存放資料值的數組的容量。

       在前面的介紹中,我們提到資料的儲存格式,這一點,我們可以從MatrixCursor如何獲得某一列的值看出來:

/**     * 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];    }

       mPos為當前行,其擷取第column 列的值為mPos * columnCount + column 。

      另外,在MatrixCursor中,定義了一個行構造器類。該類定義了某一行在data中的存放位置,由改行第一列所在位置和最後一列所在位置來定義。其中有定義了獲得某一列的值的函數getString(int column),getShort(int column)等函數,大家是否會覺得這些函數名很熟悉,在基於sqlite的content provider是否經常用到?

 /**     * 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 boolean isNull(int column) {        return get(column) == null;    }}

        MatrixCursor類中還定義了如何增加行的函數:

/**     * 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);        }    }

         這些函數都比較簡單,所以就不詳細介紹了。但是需要注意一點,其中ensureCapacity函數,用於確認,當前data的容量是否已經用完了,如果用完,需要將其容量擴充為原來的兩倍,這樣就能存放新加入行的資料了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.