您的位置:首页 > 移动开发 > Android开发

深入分析android中的Cursor 对象是如何获得的

2015-12-02 10:15 751 查看
最近在开发一个app应用的时候,需要用到数据库,以前都只是调用了接口,完成了功能,就没有关注过太多的细节东西,今天去仔细的分析了android中创建 Cursor对象的源码,和大家分享一下。

首先需要定义一个Cursor对象cursor,在定义一个SQLiteDataBase对象db,代码如下:

cursor = db.rawQuery(sql, selectionArgs);

跟着追踪回源码:

public Cursor rawQuery(String sql, String[] selectionArgs)

{ //调用rawQueryWithFactory函数,函数定义如下

return rawQueryWithFactory(null, sql, selectionArgs, null);

}

public Cursor rawQueryWithFactory(

CursorFactory cursorFactory, String sql, String[] selectionArgs,

String editTable) {

verifyDbIsOpen();

BlockGuard.getThreadPolicy().onReadFromDisk();

long timeStart = 0;

if (false || mSlowQueryThreshold != -1) {

timeStart = System.currentTimeMillis();

}

SQLiteDatabase db = getDbConnection(sql);

//此处又是分析的重点,需要追踪回SQLiteDirectCursorDriver类

SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(db, sql, editTable);

Cursor cursor = null;

try {

//此处才是获得的cursor对象driver.query方法只是对SQLiteCursorDriver接口中的方法的实现

cursor = driver.query(

cursorFactory != null ? cursorFactory : mFactory,

selectionArgs);

} finally {

if (false || mSlowQueryThreshold != -1) {

// Force query execution

int count = -1;

if (cursor != null) {

count = cursor.getCount();

}

long duration = System.currentTimeMillis() - timeStart;

if (false || duration >= mSlowQueryThreshold) {

Log.v(SQLiteCursor.TAG,

"query (" + duration + " ms): " + driver.toString() + ", args are "

+ (selectionArgs != null

? TextUtils.join(",", selectionArgs)

: "<null>") + ", count is " + count);

}

}

releaseDbConnection(db);

}

return cursor;



//query方法的实现如下

public Cursor query(CursorFactory factory, String[] selectionArgs) {

SQLiteQuery query = null;

try {

mDatabase.lock(mSql);

mDatabase.closePendingStatements();

query = new SQLiteQuery(mDatabase, mSql, 0, selectionArgs);

// Create the cursor

if (factory == null) {

//此处又创建一个SQLiteCursor对象,通过这个对象的创建,最终获得。

mCursor = new SQLiteCursor(this, mEditTable, query);

} else {

mCursor = factory.newCursor(mDatabase, this, mEditTable, query);

}

mQuery = query;

query = null;

return mCursor;

} finally {

// Make sure this object is cleaned up if something happens

if (query != null) query.close();

mDatabase.unlock();

}

}

}

//其实归根结底Cursor中接口的方法在此处定义

public abstract class AbstractCursor implements CrossProcessCursor {

private static final String TAG = "Cursor";

DataSetObservable mDataSetObservable = new DataSetObservable();

ContentObservable mContentObservable = new ContentObservable();

Bundle mExtras = Bundle.EMPTY;

/* -------------------------------------------------------- */

/* These need to be implemented by subclasses */

abstract public int getCount();

abstract public String[] getColumnNames();

abstract public String getString(int column);

abstract public short getShort(int column);

abstract public int getInt(int column);

abstract public long getLong(int column);

abstract public float getFloat(int column);

abstract public double getDouble(int column);

abstract public boolean isNull(int column);

public int getType(int column) {

throw new UnsupportedOperationException();

}

// TODO implement getBlob in all cursor types

public byte[] getBlob(int column) {

throw new UnsupportedOperationException("getBlob is not supported");

}

/* -------------------------------------------------------- */

/* Methods that may optionally be implemented by subclasses */

/**

* If the cursor is backed by a {@link CursorWindow}, returns a pre-filled

* window with the contents of the cursor, otherwise null.

*

* @return The pre-filled window that backs this cursor, or null if none.

*/

public CursorWindow getWindow() {

return null;

}

public int getColumnCount() {

return getColumnNames().length;

}

public void deactivate() {

onDeactivateOrClose();

}

/** @hide */

protected void onDeactivateOrClose() {

if (mSelfObserver != null) {

mContentResolver.unregisterContentObserver(mSelfObserver);

mSelfObserverRegistered = false;

}

mDataSetObservable.notifyInvalidated();

}

public boolean requery() {

if (mSelfObserver != null && mSelfObserverRegistered == false) {

mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);

mSelfObserverRegistered = true;

}

mDataSetObservable.notifyChanged();

return true;

}

public boolean isClosed() {

return mClosed;

}

public void close() {

mClosed = true;

mContentObservable.unregisterAll();

onDeactivateOrClose();

}

/**

* This function is called every time the cursor is successfully scrolled

* to a new position, giving the subclass a chance to update any state it

* may have. If it returns false the move function will also do so and the

* cursor will scroll to the beforeFirst position.

*

* @param oldPosition the position that we're moving from

* @param newPosition the position that we're moving to

* @return true if the move is successful, false otherwise

*/

public boolean onMove(int oldPosition, int newPosition) {

return true;

}

public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {

// Default implementation, uses getString

String result = getString(columnIndex);

if (result != null) {

char[] data = buffer.data;

if (data == null || data.length < result.length()) {

buffer.data = result.toCharArray();

} else {

result.getChars(0, result.length(), data, 0);

}

buffer.sizeCopied = result.length();

} else {

buffer.sizeCopied = 0;

}

}

/* -------------------------------------------------------- */

/* Implementation */

public AbstractCursor() {

mPos = -1;

mRowIdColumnIndex = -1;

mCurrentRowID = null;

mUpdatedRows = new HashMap<Long, Map<String, Object>>();

}

public final int getPosition() {

return mPos;

}

public final boolean moveToPosition(int position) {

// Make sure position isn't past the end of the cursor

final int count = getCount();

if (position >= count) {

mPos = count;

return false;

}

// Make sure position isn't before the beginning of the cursor

if (position < 0) {

mPos = -1;

return false;

}

// Check for no-op moves, and skip the rest of the work for them

if (position == mPos) {

return true;

}

boolean result = onMove(mPos, position);

if (result == false) {

mPos = -1;

} else {

mPos = position;

if (mRowIdColumnIndex != -1) {

mCurrentRowID = Long.valueOf(getLong(mRowIdColumnIndex));

}

}

return result;

}

/**

* Copy data from cursor to CursorWindow

* @param position start position of data

* @param window

*/

public void fillWindow(int position, CursorWindow window) {

if (position < 0 || position >= getCount()) {

return;

}

window.acquireReference();

try {

int oldpos = mPos;

mPos = position - 1;

window.clear();

window.setStartPosition(position);

int columnNum = getColumnCount();

window.setNumColumns(columnNum);

while (moveToNext() && window.allocRow()) {

for (int i = 0; i < columnNum; i++) {

String field = getString(i);

if (field != null) {

if (!window.putString(field, mPos, i)) {

window.freeLastRow();

break;

}

} else {

if (!window.putNull(mPos, i)) {

window.freeLastRow();

break;

}

}

}

}

mPos = oldpos;

} catch (IllegalStateException e){

// simply ignore it

} finally {

window.releaseReference();

}

}

public final boolean move(int offset) {

return moveToPosition(mPos + offset);

}

public final boolean moveToFirst() {

return moveToPosition(0);

}

public final boolean moveToLast() {

return moveToPosition(getCount() - 1);

}

public final boolean moveToNext() {

return moveToPosition(mPos + 1);

}

public final boolean moveToPrevious() {

return moveToPosition(mPos - 1);

}

public final boolean isFirst() {

return mPos == 0 && getCount() != 0;

}

public final boolean isLast() {

int cnt = getCount();

return mPos == (cnt - 1) && cnt != 0;

}

public final boolean isBeforeFirst() {

if (getCount() == 0) {

return true;

}

return mPos == -1;

}

public final boolean isAfterLast() {

if (getCount() == 0) {

return true;

}

return mPos == getCount();

}

public int getColumnIndex(String columnName) {

// Hack according to bug 903852

final int periodIndex = columnName.lastIndexOf('.');

if (periodIndex != -1) {

Exception e = new Exception();

Log.e(TAG, "requesting column name with table name -- " + columnName, e);

columnName = columnName.substring(periodIndex + 1);

}

String columnNames[] = getColumnNames();

int length = columnNames.length;

for (int i = 0; i < length; i++) {

if (columnNames[i].equalsIgnoreCase(columnName)) {

return i;

}

}

if (false) {

if (getCount() > 0) {

Log.w("AbstractCursor", "Unknown column " + columnName);

}

}

return -1;

}

public int getColumnIndexOrThrow(String columnName) {

final int index = getColumnIndex(columnName);

if (index < 0) {

throw new IllegalArgumentException("column '" + columnName + "' does not exist");

}

return index;

}

public String getColumnName(int columnIndex) {

return getColumnNames()[columnIndex];

}

public void registerContentObserver(ContentObserver observer) {

mContentObservable.registerObserver(observer);

}

public void unregisterContentObserver(ContentObserver observer) {

// cursor will unregister all observers when it close

if (!mClosed) {

mContentObservable.unregisterObserver(observer);

}

}

/**

* This is hidden until the data set change model has been re-evaluated.

* @hide

*/

protected void notifyDataSetChange() {

mDataSetObservable.notifyChanged();

}

/**

* This is hidden until the data set change model has been re-evaluated.

* @hide

*/

protected DataSetObservable getDataSetObservable() {

return mDataSetObservable;

}

public void registerDataSetObserver(DataSetObserver observer) {

mDataSetObservable.registerObserver(observer);

}

public void unregisterDataSetObserver(DataSetObserver observer) {

mDataSetObservable.unregisterObserver(observer);

}

/**

* Subclasses must call this method when they finish committing updates to notify all

* observers.

*

* @param selfChange

*/

protected void onChange(boolean selfChange) {

synchronized (mSelfObserverLock) {

mContentObservable.dispatchChange(selfChange);

if (mNotifyUri != null && selfChange) {

mContentResolver.notifyChange(mNotifyUri, mSelfObserver);

}

}

}

/**

* Specifies a content URI to watch for changes.

*

* @param cr The content resolver from the caller's context.

* @param notifyUri The URI to watch for changes. This can be a

* specific row URI, or a base URI for a whole class of content.

*/

public void setNotificationUri(ContentResolver cr, Uri notifyUri) {

synchronized (mSelfObserverLock) {

mNotifyUri = notifyUri;

mContentResolver = cr;

if (mSelfObserver != null) {

mContentResolver.unregisterContentObserver(mSelfObserver);

}

mSelfObserver = new SelfContentObserver(this);

mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);

mSelfObserverRegistered = true;

}

}

public Uri getNotificationUri() {

return mNotifyUri;

}

public boolean getWantsAllOnMoveCalls() {

return false;

}

/**

* Sets a {@link Bundle} that will be returned by {@link #getExtras()}. <code>null</code> will

* be converted into {@link Bundle#EMPTY}.

*

* @param extras {@link Bundle} to set.

* @hide

*/

public void setExtras(Bundle extras) {

mExtras = (extras == null) ? Bundle.EMPTY : extras;

}

public Bundle getExtras() {

return mExtras;

}

public Bundle respond(Bundle extras) {

return Bundle.EMPTY;

}

/**

* @deprecated Always returns false since Cursors do not support updating rows

*/

@Deprecated

protected boolean isFieldUpdated(int columnIndex) {

return false;

}

/**

* @deprecated Always returns null since Cursors do not support updating rows

*/

@Deprecated

protected Object getUpdatedField(int columnIndex) {

return null;

}

/**

* This function throws CursorIndexOutOfBoundsException if

* the cursor position is out of bounds. Subclass implementations of

* the get functions should call this before attempting

* to retrieve data.

*

* @throws CursorIndexOutOfBoundsException

*/

protected void checkPosition() {

if (-1 == mPos || getCount() == mPos) {

throw new CursorIndexOutOfBoundsException(mPos, getCount());

}

}

@Override

protected void finalize() {

if (mSelfObserver != null && mSelfObserverRegistered == true) {

mContentResolver.unregisterContentObserver(mSelfObserver);

}

}

/**

* Cursors use this class to track changes others make to their URI.

*/

protected static class SelfContentObserver extends ContentObserver {

WeakReference<AbstractCursor> mCursor;

public SelfContentObserver(AbstractCursor cursor) {

super(null);

mCursor = new WeakReference<AbstractCursor>(cursor);

}

@Override

public boolean deliverSelfNotifications() {

return false;

}

@Override

public void onChange(boolean selfChange) {

AbstractCursor cursor = mCursor.get();

if (cursor != null) {

cursor.onChange(false);

}

}

}

/**

* @deprecated This is never updated by this class and should not be used

*/

@Deprecated

protected HashMap<Long, Map<String, Object>> mUpdatedRows;

/**

* This must be set to the index of the row ID column by any

* subclass that wishes to support updates.

*/

protected int mRowIdColumnIndex;

protected int mPos;

/**

* If {@link #mRowIdColumnIndex} is not -1 this contains contains the value of

* the column at {@link #mRowIdColumnIndex} for the current row this cursor is

* pointing at.

*/

protected Long mCurrentRowID;

protected ContentResolver mContentResolver;

protected boolean mClosed = false;

private Uri mNotifyUri;

private ContentObserver mSelfObserver;

final private Object mSelfObserverLock = new Object();

private boolean mSelfObserverRegistered;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: