看ContentResolver的query方法:
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder,
@Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(uri, "uri");
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
IContentProvider stableProvider = null;
Cursor qCursor = null;
try {
long startTime = SystemClock.uptimeMillis();
ICancellationSignal remoteCancellationSignal = null;
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
remoteCancellationSignal = unstableProvider.createCancellationSignal();
cancellationSignal.setRemote(remoteCancellationSignal);
}
try {
//无论是unstable还是stable,都是调用ContentProvider的Bp端query方法,后面可以知道,qCursor是BulkCursorToCursorAdapter类型
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
} catch (DeadObjectException e) {
// The remote process has died... but we only hold an unstable
// reference though, so we might recover!!! Let's try!!!!
// This is exciting!!1!!1!!!!1
unstableProviderDied(unstableProvider);
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
}
qCursor = stableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
}
if (qCursor == null) {
return null;
}
// Force query execution. Might fail and throw a runtime exception here.
qCursor.getCount();
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
// Wrap the cursor object into CursorWrapperInner object.
final IContentProvider provider = (stableProvider != null) ? stableProvider
: acquireProvider(uri);
final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);//从ContentResolver返回的是一个CursorWrapperInner
stableProvider = null;
qCursor = null;
return wrapper;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
return null;
} finally {
if (qCursor != null) {
qCursor.close();
}
if (cancellationSignal != null) {
cancellationSignal.setRemote(null);
}
if (unstableProvider != null) {
releaseUnstableProvider(unstableProvider);
}
if (stableProvider != null) {
releaseProvider(stableProvider);
}
}
}
从ContentProviderProxy#query()入手:
public Cursor query(String callingPkg, Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
throws RemoteException {
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();//注意这个类型的对象
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);//写入binder标志
data.writeString(callingPkg);//写入方法的参数
url.writeToParcel(data, 0);
int length = 0;
if (projection != null) {
length = projection.length;
}
data.writeInt(length);
for (int i = 0; i < length; i++) {
data.writeString(projection[i]);
}
data.writeString(selection);
if (selectionArgs != null) {
length = selectionArgs.length;
} else {
length = 0;
}
data.writeInt(length);
for (int i = 0; i < length; i++) {
data.writeString(selectionArgs[i]);//写参数
}
data.writeString(sortOrder);//写参数
data.writeStrongBinder(adaptor.getObserver().asBinder());//传递一个ContentObserver,一个Binder对象
data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null);
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);//向Bn端发起请求
DatabaseUtils.readExceptionFromParcel(reply);//读取返回值
if (reply.readInt() != 0) {
//所有参数都包含在了BuklCursorDescriptor中,包括IBulkCursor和CursorWindow,后面会分析这个createFromParcel(),
BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);//读取一个序列化对象,并反序列化该对象
adaptor.initialize(d);//把BuildCursorDescriptor和adaptor绑定,最后返回这个Cursor,所以从ContentProvider的Bp端返回的是BulkCursorToCursorAdapter
} else {
adaptor.close();
adaptor = null;
}
return adaptor;
} catch (RemoteException ex) {
adaptor.close();
throw ex;
} catch (RuntimeException ex) {
adaptor.close();
throw ex;
} finally {
data.recycle();
reply.recycle();
}
}
主要向ContentProvider的Bn端发送了一个ContentObserver的Bp端,还有进行查询的SQL语句信息
分析BulkCursorDescriptor.CREATOR.createFromParcel(reply):
public final class BulkCursorDescriptor implements Parcelable {
public static final Parcelable.Creator<BulkCursorDescriptor> CREATOR =
new Parcelable.Creator<BulkCursorDescriptor>() {
@Override
public BulkCursorDescriptor createFromParcel(Parcel in) {
BulkCursorDescriptor d = new BulkCursorDescriptor();//创建对象
d.readFromParcel(in);//反序列化一个对象
return d;
}
@Override
public BulkCursorDescriptor[] newArray(int size) {
return new BulkCursorDescriptor[size];
}
};
public IBulkCursor cursor;//重要成员
public String[] columnNames;
public boolean wantsAllOnMoveCalls;
public int count;
public CursorWindow window;/重要成员
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeStrongBinder(cursor.asBinder());
out.writeStringArray(columnNames);
out.writeInt(wantsAllOnMoveCalls ? 1 : 0);
out.writeInt(count);
if (window != null) {
out.writeInt(1);
window.writeToParcel(out, flags);
} else {
out.writeInt(0);
}
}
public void readFromParcel(Parcel in) {
cursor = BulkCursorNative.asInterface(in.readStrongBinder());//获取一个Bp对象,IBulkCursor
columnNames = in.readStringArray();
wantsAllOnMoveCalls = in.readInt() != 0;
count = in.readInt();
if (in.readInt() != 0) {
window = CursorWindow.CREATOR.createFromParcel(in);//查询到的行数不为0,则获取这个共享内存对象
}
}
}
接收了来自ContentProvider Bn端的CursorToBulkCursorAdaptor的Bp端。CursorToBulkCursorAdaptor继承了和实现了BulkCursorNative,一个反序列化的CursorWindow。
看ContentProvider的Bn端是怎么处理请求并返回数据,从ContentProviderNative的onTransaction()开始分析:
case QUERY_TRANSACTION://这是处理query请求的
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
// String[] projection
int num = data.readInt();
String[] projection = null;
if (num > 0) {
projection = new String[num];
for (int i = 0; i < num; i++) {
projection[i] = data.readString();
}
}
// String selection, String[] selectionArgs...
String selection = data.readString();
num = data.readInt();
String[] selectionArgs = null;
if (num > 0) {
selectionArgs = new String[num];
for (int i = 0; i < num; i++) {
selectionArgs[i] = data.readString();
}
}
String sortOrder = data.readString();
IContentObserver observer = IContentObserver.Stub.asInterface(
data.readStrongBinder());//创建一个ContentObserver的Bp端
ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
data.readStrongBinder());
Cursor cursor = query(callingPkg, url, projection, selection, selectionArgs,
sortOrder, cancellationSignal);//调用Bn端的query方法,并返回一个Cursor,这个Cursor是SQLiteCursor类型
if (cursor != null) {
CursorToBulkCursorAdaptor adaptor = null;
try {
adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
getProviderName());//创建一个包括Cursor和ContentObserver的对象
cursor = null;
BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();//获取一个Parcelable对象,里面还调用了一个重要方法
adaptor = null;
reply.writeNoException();
reply.writeInt(1);
//将
d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);//将BulkCursorDescriptor中的IBulkCursor写到reply中
} finally {
// Close cursor if an exception was thrown while constructing the adaptor.
if (adaptor != null) {
adaptor.close();
}
if (cursor != null) {
cursor.close();
}
}
} else {
reply.writeNoException();
reply.writeInt(0);
}
return true;
}
public void writeToParcel(Parcel out, int flags) {
out.writeStrongBinder(cursor.asBinder());
out.writeStringArray(columnNames);
out.writeInt( ? 1 : 0);
out.writeInt(count)wantsAllOnMoveCalls;
if (window != null) {
out.writeInt(1);
window.writeToParcel(out, flags);
} else {
out.writeInt(0);
}
}
CursorWindow的writeToParcel():
public void writeToParcel(Parcel dest, int flags) {
acquireReference();
try {
dest.writeInt(mStartPos);//写入数据在共享内存的起始位置
nativeWriteToParcel(mWindowPtr, dest);//写入对应native层CursorWindow实例的指针
} finally {
releaseReference();
}
if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
releaseReference();
}
}
可以看到ContentProvider的Bn端给Bp端写入IBulkCursor、columnNames,还有native层CursorWindow的指针
再看看BulkCursorDescrptor的生成,CursorToBulkCursorAdaptor#getBulkCursorDescriptor():
/**
* Returns an object that contains sufficient metadata to reconstruct
* the cursor remotely. May throw if an error occurs when executing the query
* and obtaining the row count.
*/
public BulkCursorDescriptor getBulkCursorDescriptor() {
synchronized (mLock) {
throwIfCursorIsClosed();
BulkCursorDescriptor d = new BulkCursorDescriptor();
d.cursor = this;
d.columnNames = mCursor.getColumnNames();
d.wantsAllOnMoveCalls = mCursor.getWantsAllOnMoveCalls();
d.count = mCursor.getCount();//mCursor指向的SQLiteCursor
d.window = mCursor.getWindow();
if (d.window != null) {
// Acquire a reference to the window because its reference count will be
// decremented when it is returned as part of the binder call reply parcel.
d.window.acquireReference();
}
return d;
}
}
SQLiteCursor#getCount():这个方法会将查询到的内容写到共享内存中。至于这个SQLiteCursor是怎么来的,后面会在分析,其实SQLite的query主要就是需要native层的三样东西,SQLiteDatabase的指针(6.0之后后由SQLiteConnection持有),statement指针(主要是sql语句),CursorWindow指针。看SQLiteCursor#getCount()源码:
@Override
public int getCount() {
if (mCount == NO_COUNT) {
fillWindow(0);//分析这方法
}
return mCount;
}
SQLiteCursor#fillWindow():
private void fillWindow(int requiredPos) {
clearOrCreateWindow(getDatabase().getPath());
try {
if (mCount == NO_COUNT) {
int startPos = DatabaseUtils.cursorPickFillWindowStartPosition(requiredPos, 0);//内存起始位置
mCount = mQuery.fillWindow(mWindow, startPos, requiredPos, true);//mQuery是SQLiteQuery类型
mCursorWindowCapacity = mWindow.getNumRows();//计算这个共享内存可以存多少行记录
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "received count(*) from native_fill_window: " + mCount);
}
} else {
int startPos = DatabaseUtils.cursorPickFillWindowStartPosition(requiredPos,
mCursorWindowCapacity);
mQuery.fillWindow(mWindow, startPos, requiredPos, false);//mQuery是SQLiteQuery类型
}
} catch (RuntimeException ex) {
// Close the cursor window if the query failed and therefore will
// not produce any results. This helps to avoid accidentally leaking
// the cursor window if the client does not correctly handle exceptions
// and fails to close the cursor.
closeWindow();
throw ex;
}
}
看SQLiteQuery#fillWindow():
int fillWindow(CursorWindow window, int startPos, int requiredPos, boolean countAllRows) {
acquireReference();
try {
window.acquireReference();//增加引用
try {
int numRows = getSession().executeForCursorWindow(getSql(), getBindArgs(),
window, startPos, requiredPos, countAllRows, getConnectionFlags(),
mCancellationSignal);//getSession返回的实例是SQLiteSesion
return numRows;
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
} catch (SQLiteException ex) {
Log.e(TAG, "exception: " + ex.getMessage() + "; query: " + getSql());
throw ex;
} finally {
window.releaseReference();
}
} finally {
releaseReference();
}
}
看SQLiteSession#executeForCursorWindow():
public int executeForCursorWindow(String sql, Object[] bindArgs,
CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
int connectionFlags, CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
if (window == null) {
throw new IllegalArgumentException("window must not be null.");
}
if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
window.clear();
return 0;
}
//获取一个SQLiteConnection,让mConnection指向该connection,代表了一个数据库连接,肯定持有了SQLiteDatabase指针
acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
return mConnection.executeForCursorWindow(sql, bindArgs,//分析这个方法
window, startPos, requiredPos, countAllRows,
cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
}
看SQLiteConnection#executeForCursorWindow():
public int executeForCursorWindow(String sql, Object[] bindArgs,
CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
if (window == null) {
throw new IllegalArgumentException("window must not be null.");
}
window.acquireReference();//对window增加引用
try {
int actualPos = -1;
int countedRows = -1;
int filledRows = -1;
final int cookie = mRecentOperations.beginOperation("executeForCursorWindow",
sql, bindArgs);
try {
final PreparedStatement statement = acquirePreparedStatement(sql);//对应native层的sqlite3_stmt
try {
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
attachCancellationSignal(cancellationSignal);
try {
//这个是一个jni方法,在android_base_SQLiteConnection.cpp中
final long result = nativeExecuteForCursorWindow(
mConnectionPtr, statement.mStatementPtr, window.mWindowPtr,
startPos, requiredPos, countAllRows);//mConnectionPtr、mStatementPtr、mWindowPtr就是对应native层对象的指针
actualPos = (int)(result >> 32);
countedRows = (int)result;
filledRows = window.getNumRows();
window.setStartPosition(actualPos);
return countedRows;//返回查询到的行数
} finally {
detachCancellationSignal(cancellationSignal);
}
} finally {
releasePreparedStatement(statement);
}
} catch (RuntimeException ex) {
mRecentOperations.failOperation(cookie, ex);
throw ex;
} finally {
if (mRecentOperations.endOperationDeferLog(cookie)) {
mRecentOperations.logOperation(cookie, "window='" + window
+ "', startPos=" + startPos
+ ", actualPos=" + actualPos
+ ", filledRows=" + filledRows
+ ", countedRows=" + countedRows);
}
}
} finally {
window.releaseReference();//使用完后释放引用,引用减1
}
}
看android_base_SQLiteConnection#nativeExecuteForCursorWindow():
static jlong nativeExecuteForCursorWindow(JNIEnv* env, jclass clazz,
jlong connectionPtr, jlong statementPtr, jlong windowPtr,
jint startPos, jint requiredPos, jboolean countAllRows) {
SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);//把long值转换成对应的类型的指针,下面两个也是
sqlite3_stmt* statement = reinterpret_cast<sqlite3_stmt*>(statementPtr);
CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
status_t status = window->clear();
if (status) {
String8 msg;
msg.appendFormat("Failed to clear the cursor window, status=%d", status);
throw_sqlite3_exception(env, connection->db, msg.string());
return 0;
}
int numColumns = sqlite3_column_count(statement);
status = window->setNumColumns(numColumns);//设置每行有多少列
if (status) {
String8 msg;
msg.appendFormat("Failed to set the cursor window column count to %d, status=%d",
numColumns, status);
throw_sqlite3_exception(env, connection->db, msg.string());
return 0;
}
int retryCount = 0;
int totalRows = 0;
int addedRows = 0;
bool windowFull = false;
bool gotException = false;
//下面这个循环,它将遍历SQL的结果集,并将数据取出来保存到CursorWindow对象中
while (!gotException && (!windowFull || countAllRows)) {
int err = sqlite3_step(statement);//有点像iterator,一次取一行
if (err == SQLITE_ROW) {//正常的是进入这里,SQLite_ROW表示获取到了一行
LOG_WINDOW("Stepped statement %p to row %d", statement, totalRows);
retryCount = 0;//后面在忙时会重复尝试连接,retry大于50次就放弃
totalRows += 1;//每次取了一行都加1
// Skip the row if the window is full or we haven't reached the start position yet.
if (startPos >= totalRows || windowFull) {
continue;
}
CopyRowResult cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);//将数据写到window中,就是写到共享内存中
if (cpr == CPR_FULL && addedRows && startPos + addedRows <= requiredPos) {
// We filled the window before we got to the one row that we really wanted.
// Clear the window and start filling it again from here.
// TODO: Would be nicer if we could progressively replace earlier rows.
window->clear();
window->setNumColumns(numColumns);
startPos += addedRows;
addedRows = 0;
cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
}
if (cpr == CPR_OK) {
addedRows += 1;
} else if (cpr == CPR_FULL) {
windowFull = true;
} else {
gotException = true;
}
} else if (err == SQLITE_DONE) {//表示上次已经获取最后一行的,这次取的话就会进入这里
// All rows processed, bail
LOG_WINDOW("Processed all rows");
break;
} else if (err == SQLITE_LOCKED || err == SQLITE_BUSY) {//数据库忙或者锁被占用了
// The table is locked, retry
LOG_WINDOW("Database locked, retrying");
if (retryCount > 50) {
ALOGE("Bailing on database busy retry");
throw_sqlite3_exception(env, connection->db, "retrycount exceeded");
gotException = true;
} else {
// Sleep to give the thread holding the lock a chance to finish
usleep(1000);
retryCount++;
}
} else {
throw_sqlite3_exception(env, connection->db);
gotException = true;
}
}
LOG_WINDOW("Resetting statement %p after fetching %d rows and adding %d rows"
"to the window in %d bytes",
statement, totalRows, addedRows, window->size() - window->freeSpace());
sqlite3_reset(statement);
// Report the total number of rows on request.
if (startPos > totalRows) {
ALOGE("startPos %d > actual rows %d", startPos, totalRows);
}
jlong result = jlong(startPos) << 32 | jlong(totalRows);
return result;
}
看看CursorWindow的创建过程,首先要从SQLiteCursor#fillWindow()中的调用 clearOrCreateWindow (getDatabase().getPath());分析起,该方法是其父类AbstractWindowedCursor实现的。
protected void clearOrCreateWindow(String name) {
if (mWindow == null) {
mWindow = new CursorWindow(name);
} else {
mWindow.clear();
}
}
看CursorWindow的构造方法:
public CursorWindow(String name) {
mStartPos = 0;
mName = name != null && name.length() != 0 ? name : "<unnamed>";
if (sCursorWindowSize < 0) {
/** The cursor window size. resource xml file specifies the value in kB.
* convert it to bytes here by multiplying with 1024.
*/
sCursorWindowSize = Resources.getSystem().getInteger(
com.android.internal.R.integer.config_cursorWindowSize) * 1024;//window的大小就是这么大,config_cursorWindowSize为2048
}
//创建一个native层的CursorWindow方法,java层的CursorWindow持有native层window的指针到mWindowPtr
mWindowPtr = nativeCreate(mName, sCursorWindowSize);
if (mWindowPtr == 0) {
throw new CursorWindowAllocationException("Cursor window allocation of " +
(sCursorWindowSize / 1024) + " kb failed. " + printStats());
}
mCloseGuard.open("close");
recordNewWindow(Binder.getCallingPid(), mWindowPtr);
}
看看nativeCreate(),在android_base_CursorWindow.cpp中:
static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring nameObj, jint cursorWindowSize) {
String8 name;
const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
name.setTo(nameStr);
env->ReleaseStringUTFChars(nameObj, nameStr);
CursorWindow* window;
status_t status = CursorWindow::create(name, cursorWindowSize, &window);
if (status || !window) {
ALOGE("Could not allocate CursorWindow '%s' of size %d due to error %d.",
name.string(), cursorWindowSize, status);
return 0;
}
LOG_WINDOW("nativeInitializeEmpty: window = %p", window);
return reinterpret_cast<jlong>(window);
}
下面是是ContentProvider的Bp端调用Bn端的query方法的交互过程,其中左边ContentProviderNative应改成ContentProviderProxy
下面先看看ContentProvider的Bn端query():
ContentProvider$Transport extends ContentProviderNative,看ContentProvider$Transport#query():
@Override
public Cursor query(String callingPkg, Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
ICancellationSignal cancellationSignal) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
// The caller has no access to the data, so return an empty cursor with
// the columns in the requested order. The caller may ask for an invalid
// column and we would not catch that but this is not a problem in practice.
// We do not call ContentProvider#query with a modified where clause since
// the implementation is not guaranteed to be backed by a SQL database, hence
// it may not handle properly the tautology where clause we would have created.
if (projection != null) {
return new MatrixCursor(projection, 0);
}
// Null projection means all columns but we have no idea which they are.
// However, the caller may be expecting to access them my index. Hence,
// we have to execute the query as if allowed to get a cursor with the
// columns. We then use the column names to return an empty cursor.
Cursor cursor = ContentProvider.this.query(uri, projection, selection,
selectionArgs, sortOrder, CancellationSignal.fromTransport(
cancellationSignal));
if (cursor == null) {
return null;
}
// Return an empty cursor for all columns.
return new MatrixCursor(cursor.getColumnNames(), 0);
}
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.query(
uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));//最终调用ContentProvider子类的query()
} finally {
setCallingPackage(original);
}
}
ContentProvider子类query最终会去SQLiteDatabase的query方法,无论是SQLiteDatabase#query还是rawQuery,最终会去到SQLiteDatabase#queryWithFactory():
public Cursor queryWithFactory(CursorFactory cursorFactory,
boolean distinct, String table, String[] columns,
String selection, String[] selectionArgs, String groupBy,
String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
acquireReference();
try {
//根据各种查询参数构造一个SQL的SELECT语句
String sql = SQLiteQueryBuilder.buildQueryString(
distinct, table, columns, selection, groupBy, having, orderBy, limit);
//其中cursorFactory为null
return rawQueryWithFactory(cursorFactory, sql, selectionArgs,
findEditTable(table), cancellationSignal);
} finally {
releaseReference();
}
}
public Cursor rawQueryWithFactory(
CursorFactory cursorFactory, String sql, String[] selectionArgs,
String editTable, CancellationSignal cancellationSignal) {
acquireReference();
try {
SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
cancellationSignal);
return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory,
selectionArgs);
} finally {
releaseReference();
}
}
看SQLiteDirectCursorDriver#query():
public Cursor query(CursorFactory factory, String[] selectionArgs) {
final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancellationSignal);
final Cursor cursor;
try {
query.bindAllArgsAsStrings(selectionArgs);
if (factory == null) {//在rawQueryWithFactory方法中说过,这个参数为null
cursor = new SQLiteCursor(this, mEditTable, query);//从SQLiteDatabase返回的就是SQLiteCursor
} else {
cursor = factory.newCursor(mDatabase, this, mEditTable, query);
}
} catch (RuntimeException ex) {
query.close();
throw ex;
}
mQuery = query;
return cursor;
}
上面的分析,现在在ContentProvider的Bn端已经把数据查询后放到了CursorWindow中(前面说了,在调用SQLiteCursor.getCount后,就开始了真正的查询操作)。那么现在就是要等Bn端获取共享内存的内容了,那么Bn端首先要获取CursorWindow指针。CursorWindow就是对一块共享内存的封装。另外我们也看到了如何将执行SELECT语句后得到的结果集填充到这块共享内存中。但是这块内存现在还仅属于服务端进程,只有客户端进程得到这块内存后,客户端才能真正获取执行SELECT后的结果。
现在就要开始回到客户端分析了ContentProviderProxy返回的是BulkCursorToCursorAdapter,而ContentResolver返回的是CursorWrapperInner,CursorWrapperInner封装了BulkCursorToCursorAdapter。所以接下来将分析BulkCursorToCursorAdapter和CursorWrapperInner.
moveToFirst函数分析
客户端还未拿到那块至关重要的共享内存,即进程间的数据通道还没打通。那么,数据通道是何时打通的,就是调用moveToFirst才打通的,所以使用cursor获取数据前,必须调用moveToFirst,其中CursorWrapperInner在ContentProviderClient.java 中。moveToFirst就是在CursorWrapper实现的。
[-->CursorWrapper.java::moveToFirst]
publicboolean moveToFirst() {
//mCursor指向BulkCursorToCursorAdaptor
returnmCursor.moveToFirst();
}
mCursor成员变量的真实类型是BulkCursorToCursorAdaptor,但其moveToFirst函数却是该类的老祖宗AbstractCursor实现,代码如下:
[-->AbstractCursor.java::moveToFirst]
publicfinal boolean moveToFirst() {
returnmoveToPosition(0);//调用moveToPosition,直接来看该函数
}
//moveToPosition分析,其参数position表示将移动游标到哪一行
public final boolean moveToPosition(int position){
//getCount返回结果集中的行数,这个值在搭建Binder通信通道时,已经由服务端计算并返回
//给客户端了
final int count = getCount();
//mPos变量记录了当前游标的位置,该变量初值为-1
if(position >= count) {
mPos = count;
return false;
}
if(position < 0) {
mPos = -1;
returnfalse;
}
if(position == mPos) return true;
//onMove函数为抽象函数,由子类实现
booleanresult = onMove(mPos, position);
if(result == false) mPos = -1;
else {
mPos = position;
if (mRowIdColumnIndex != -1) {
mCurrentRowID = Long.valueOf(getLong(mRowIdColumnIndex));
}
}
returnresult;
}
在上边代码中,moveToPosition将调用子类实现的onMove函数。在本例中,子类就是BulkCursorToCursorAdaptor,接下来看它的onMove函数。
(1) BulkCursorToCursorAdaptor的onMove函数分析
[-->BulkCursorToCursorAdaptor.java::onMove]
public boolean onMove(int oldPosition, intnewPosition) {
throwIfCursorIsClosed();
try {
//mWindow的类型就是CursorWindow。第一次调用该函数,mWindow为null
if(mWindow == null
||newPosition < mWindow.getStartPosition()
|| newPosition >= mWindow.getStartPosition()+
mWindow.getNumRows()){
/*
mBulkCurosr用于和位于服务端的IBulkCursor Bn端通信,其getWindow函数
将返回一个CursorWindow类型的对象。也就是说,调用完getWindow函数后,
客户端进程就得到了一个CursorWindow,从此,客户端和服务端之间的数据通道就
打通了
*/
setWindow(mBulkCursor.getWindow(newPosition));
}else if (mWantsAllOnMoveCalls) {
mBulkCursor.onMove(newPosition);
}
} ......
if (mWindow== null) return false;
returntrue;
}
建立数据通道的关键函数是IBulkCurosr的getWindow。对于客户端而言,IBulkCursor Bp端对象的类型是BulkCursorProxy,下面介绍它的getWindow函数。
(2) BulkCursorProxy的 getWindow函数分析
[-->BulkCursorNative.java::BulkCursorProxy:getWindow]
public CursorWindow getWindow(int startPos) throwsRemoteException
{
Parceldata = Parcel.obtain();
Parcelreply = Parcel.obtain();
try {
data.writeInterfaceToken(IBulkCursor.descriptor);
data.writeInt(startPos);
mRemote.transact(GET_CURSOR_WINDOW_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
CursorWindow window = null;
if(reply.readInt() == 1) {
/*
根据服务端reply包构造一个本地的CursorWindow对象,读者可自行研究
newFromParcel函数,其内部会调用nativeCreateFromParcel函数以创建
一个Native的CursorWindow对象。整个过程就是笔者在前面提到的反序列化过程
*/
window = CursorWindow.newFromParcel(reply);
}
return window;
} ......
}
再来看IBulkCursor Bn端的getWindow函数,此Bn端对象的真实类型是CursorToBulkCursorAdaptor。
(3) CursorToBulkCursorAdaptor的 getWindow函数分析
[-->CursorToBulkCursorAdaptor.java::getWindow]
public CursorWindow getWindow(int startPos) {
synchronized (mLock) {
throwIfCursorIsClosed();
CursorWindow window;
//mCursor是MediaProvider query返回的值,其真实类型是SQLiteCursor,满足
//下面的if条件
if(mCursor instanceof AbstractWindowedCursor) {
AbstractWindowedCursor windowedCursor =
(AbstractWindowedCursor)mCursor;
//对于本例而言,SQLiteCursor已经和一个CursorWindow绑定了,所以window的值
//不为空
window = windowedCursor.getWindow();
if (window == null) {
window = new CursorWindow(mProviderName, false);
windowedCursor.setWindow(window);
}
//调用SQLiteCursor的moveToPosition函数,该函数前面已经分析过了,在其 //内部将触发onMove函数的调用,此处将是SQLiteCursor的onMove函数
mCursor.moveToPosition(startPos);
} else {
......
}
if (window != null) {
window.acquireReference();
}
return window;
}
}
服务端返回的CursorWindow对象正是之前在count函数中创建的那个CursorWindow对象,其内部已经包含了执行本次query的查询结果。
另外,在将服务端的CursorWindow传递到客户端之前,系统会调用CursorWindow的writeToParcel函数进行序列化工作。读者可自行阅读CursorWindow的writeToParcel及其native实现nativeWriteToParcel函数。
(4) SQLiteCursor的 moveToPostion函数分析
该函数由SQLiteCursor的基类AbstractCursor实现。我们前面已经看过它的代码了,其内部的主要工作就是调用AbstractCursor子类(此处就是SQLiteCursor自己)实现onMove函数,因此可直接看SQLiteCursor的onMove函数。
[-->SQLiteCursor.java::onMove]
public boolean onMove(int oldPosition, intnewPosition) {
if(mWindow == null || newPosition < mWindow.getStartPosition() ||
newPosition >= (mWindow.getStartPosition() +
mWindow.getNumRows())) {
fillWindow(newPosition);
}
returntrue;
}
以上代码中的if判断很重要,具体解释如下:
· 当mWindow为空,即服务端未创建CursorWindow时(当然,就本例而言,CursorWindow早已在query时就创建好了),需调用fillWindow。该函数内部将调用clearOrCreateLocalWindow。如果CursorWindow不存在,则创建一个CursorWindow对象。如果已经存在,则清空CursorWindow对象的信息。
· 当newPosition小于上一次查询得到的CursorWindow的起始位置,或者newPosition大于上一次查询得到的CursorWindow的最大行位置,也需调用fillWindow。由于此时CursorWindow已经存在,则clearOrCreateLocalWindow会调用它的clear函数以清空之前保存的信息。
· 调用fillWindow后将执行SQL语句,以获得正确的结果集。例如,假设上次执行query时设置了查询从第10行开始的90条记录(即10~100行的记录),那么,当新的query若指定了从0行开始或从101行开始时,就需重新fillWindow,即将新的结果填充到CursorWindow中。如果新query查询的行数位于10~100之间,则无需再次调用fillWindow了。
这是服务端针对query做的一些优化处理,即当CursorWindow已经包含了所要求的数据时,就没有必要再次查询了。按理说,客户端也应该做类似的判断,以避免发起不必要的Binder请求。我们回过头来看客户端BulkCursorToCursorAdaptor的onMove函数。
[-->BulkCursorToCursorAdaptor.java::onMove]
public boolean onMove(int oldPosition, intnewPosition) {
throwIfCursorIsClosed();
try {
//同样,客户端也做了对应的优化处理,如果不满足if条件,客户端根本无需调用
//mBulkCurosr的getWindow函数,这样服务端也就不会收到对应的Binder请求了
if(mWindow == null
||newPosition < mWindow.getStartPosition()
|| newPosition >=mWindow.getStartPosition() +
mWindow.getNumRows()){
setWindow(mBulkCursor.getWindow(newPosition));
)
......
}
(5) moveToFirst函数分析总结
moveToFirst及相关的兄弟函数(如moveToLast和move等)的目的是移动游标位置到指定行。通过上面的代码分析,我们发现它的工作其实远不止移动游标位置这么简单。对于还未拥有CursorWindow的客户端来说,moveToFirst将导致客户端反序列化来自服务端的CursorWindow信息,从而使客户端和服务端之间的数据通道真正建立起来。