Custom cursor sample
AbstractCursor
AbstractCursor implements CrossProcessCursor protected int mPos; // index public final boolean moveToPosition(int position) // various methods -> moveToPosition -> onMove (check) public boolean onMove(int oldPosition, int newPosition) // override method
Sample Cursor Code
package com.example.test05; import android.database.AbstractCursor; import android.database.Cursor; import android.database.CursorWindow; import android.util.Log; import java.util.List; import java.util.Map; /** * Custom Cursor Sample */ public class MyCursor2 extends AbstractCursor { public static final int WINDOW_SIZE = 50; private List<Map<String, Object>> data; private CursorWindow window; public MyCursor2(List<Map<String, Object>> data) { this.data = data; window = new CursorWindow("aaa"); // fix me! (bad provider name) } @Override public int getCount() { return data.size(); } @Override public String[] getColumnNames() { return new String[]{"_id", "" , ""};// fix me! (bad column names) } // see android.database.DatabaseUtils#cursorFillWindow // public static void cursorFillWindow(final Cursor cursor, // int position, final CursorWindow window) { public void cursorFillWindow(final Cursor cursor, int position, final CursorWindow window) { if (position < 0 || position > cursor.getCount()) { return; } final int oldPos = cursor.getPosition(); final int numColumns = cursor.getColumnCount(); window.clear(); window.setStartPosition(position); window.setNumColumns(numColumns); mPos = position; //if (cursor.moveToPosition(position)) { if (true) { do { if (!window.allocRow()) { break; } for (int i = 0; i < numColumns; i++) { final int type = cursor.getType(i); final boolean success; switch (type) { case Cursor.FIELD_TYPE_NULL: success = window.putNull(position, i); break; case Cursor.FIELD_TYPE_INTEGER: success = window.putLong(cursor.getLong(i), position, i); break; case Cursor.FIELD_TYPE_FLOAT: success = window.putDouble(cursor.getDouble(i), position, i); break; case Cursor.FIELD_TYPE_BLOB: { final byte[] value = cursor.getBlob(i); success = value != null ? window.putBlob(value, position, i) : window.putNull(position, i); break; } default: // assume value is convertible to String case Cursor.FIELD_TYPE_STRING: { final String value = cursor.getString(i); success = value != null ? window.putString(value, position, i) : window.putNull(position, i); break; } } if (!success) { window.freeLastRow(); break; } } position += 1; //} while (cursor.moveToNext()); mPos++; } while (mPos < this.getCount() && position < window.getStartPosition() + WINDOW_SIZE); } //} Log.i("xxx", "window start=" + window.getStartPosition() + " numrows=" + window.getNumRows()); //cursor.moveToPosition(oldPos); mPos = oldPos; } @Override public CursorWindow getWindow() { return window; } public boolean onMove(int oldPosition, int newPosition) { if (newPosition < 0 || newPosition > this.getCount()) { return false; } CursorWindow cw = this.getWindow(); int startPos = cw.getStartPosition(); int rows = cw.getNumRows(); if (newPosition > startPos + rows -1) { // scrolling down (start position increasing) // size = 8 / window size = 3 // 0, 1, 2, 3, 4, 5, 6, 7 : index // * // * * * // * // * * * // * 5 // * * * 5 + 3 = 8 = 8 -> start = 5 // * 6 // * * * 6 + 3 = 9 > 8 -> not reading int sPos = startPos + rows -1 < 0 ? 0 : startPos + rows; if (sPos + WINDOW_SIZE <= this.getCount()) { cursorFillWindow(this, sPos, cw); } } else if (newPosition <= startPos) { // scrolling up (start position decreasing) // size = 8 / window size = 3 // 0, 1, 2, 3, 4, 5, 6, 7 : index // * not reading 0 < size - 1 // * not reading 1 < size - 1 // * reading 2 = size - 1 from 0 // * reading 3 > size - 1 int sPos = startPos - rows < 0 ? 0 : startPos - rows; if (WINDOW_SIZE -1 <= startPos) { cursorFillWindow(this, sPos, cw); } } return true; } @Override public String getString(int i) { Map<String, Object> item = data.get(getPosition()); switch (i) { case 0: return String.valueOf(item.get("id")); case 1: return (String) item.get("name"); case 2: return (String) item.get("address"); default: throw new RuntimeException("invalid id " + i); } } @Override public short getShort(int i) { return 0; } @Override public int getInt(int i) { return 0; } @Override public long getLong(int i) { return 0; } @Override public float getFloat(int i) { return 0; } @Override public double getDouble(int i) { return 0; } @Override public boolean isNull(int i) { return false; } }
Log
01-17 17:40:10.786 8715-8727/com.example.test05 I/xxx: window start=50 numrows=50 01-17 17:40:11.276 8715-8726/com.example.test05 I/xxx: window start=100 numrows=50 01-17 17:40:11.586 8715-8727/com.example.test05 I/xxx: window start=150 numrows=50 01-17 17:40:11.866 8715-8726/com.example.test05 I/xxx: window start=200 numrows=50 01-17 17:40:11.896 8715-8719/com.example.test05 D/dalvikvm: GC_CONCURRENT freed 300K, 6% free 8223K/8692K, paused 3ms+4ms, total 38ms 01-17 17:40:12.106 8715-8727/com.example.test05 I/xxx: window start=250 numrows=50 01-17 17:40:12.346 8715-8726/com.example.test05 I/xxx: window start=300 numrows=50