Contacts联系人查询过程:
(这是android2.2,2,2.3上联系人查询过程)
protected void onCreate(Bundle icicle) {
if (UI.LIST_DEFAULT.equals(action)) {
mMode = MODE_DEFAULT; //设置模式
setEmptyText(); //还未导入数据库的联系人之前,界面显示为空。
mAdapter = new ContactItemListAdapter(this);
setListAdapter(mAdapter);
getListView().setOnScrollListener(mAdapter); //设置ITEMLIST
// We manually save/restore the listview state
list.setSaveEnabled(false);
mQueryHandler = new QueryHandler(this); //获取查询实例
mJustCreated = true; //第一次打开标志
// TODO(jham) redesign this
mSyncEnabled = true;
}
// 重新执行
protected void onResume() {
boolean runQuery = true; //查询标志
if (mMode == MODE_DEFAULT) {
// If we're in default mode we need to possibly reset the mode due to a change
// in the preferences activity while we weren't running
setDefaultMode(); //设置模式
}
if (mJustCreated && runQuery) {
// We need to start a query here the first time the activity is launched, as long
// as we aren't doing a filter.
startQuery(); //开始查询
}
mJustCreated = false;
}
// 设置模式函数
private void setDefaultMode() {
// Load the preferences
log("setDefaultMode() <wlq>");
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
mDisplayOnlyPhones = prefs.getBoolean(Prefs.DISPLAY_ONLY_PHONES,
Prefs.DISPLAY_ONLY_PHONES_DEFAULT);
// Update the empty text view with the proper string, as the group may have changed
setEmptyText();
}
// 查询方法
void startQuery() {
log("startQuery() <wlq>");
mAdapter.setLoading(true);
String[] projection = getProjectionForQuery();//获取查询要查询的项目:数据库字段、表名
String callingPackage = getCallingPackage();
Uri uri = getUriToQuery(); //获取数据库链接uri=content://com.android.contacts/contacts
if (!TextUtils.isEmpty(callingPackage)) {
uri = uri.buildUpon()
.appendQueryParameter(ContactsContract.REQUESTING_PACKAGE_PARAM_KEY,
callingPackage)
.build();
}
case MODE_DEFAULT:
case MODE_PICK_CONTACT:
case MODE_PICK_OR_CREATE_CONTACT:
case MODE_INSERT_OR_EDIT_CONTACT:
mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
projection, getContactSelection(), null,
getSortOrder(projection)); //开始查询参数:查询标识、未知、数据库链接、数据库字段和表、查
//询策略(WHERE)、策略数(AND)、排序关键字
break;
}
frameworks\base\core\java\android\contect\ AsyncQueryHandler.java
// 发送查询消息
public void startQuery(int token, Object cookie, Uri uri,
String[] projection, String selection, String[] selectionArgs,
String orderBy) {
//参数:查询标识、未知、数据库链接、数据库字段和表、查询策略(WHERE)、策略数(AND)、//排序关键字
// Use the token as what so cancelOperations works properly
Message msg = mWorkerThreadHandler.obtainMessage(token);
msg.arg1 = EVENT_ARG_QUERY;
WorkerArgs args = new WorkerArgs();
args.handler = this;
args.uri = uri;
args.projection = projection;
args.selection = selection;
args.selectionArgs = selectionArgs;
args.orderBy = orderBy;
args.cookie = cookie;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);//通过消息轮询机制来实现查询
}
Packages\Provider\ContactsProvider\contactsProvider.java
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
final SQLiteDatabase db = mDbHelper.getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
String limit = getLimit(uri);
return query(db, qb, projection, selection, selectionArgs, sortOrder, groupBy, limit);
}
private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection,
String selection, String[] selectionArgs, String sortOrder, String groupBy,
String limit) {
final SQLiteDatabase db = mDbHelper.getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
String groupBy = null;
String limit = getLimit(uri);
Log.v(TAG, "query: limit=" + limit);
// TODO: Consider writing a test case for RestrictionExceptions when you
// write a new query() block to make sure it protects restricted data.
final int match = sUriMatcher.match(uri);
Log.v(TAG, "query: match=" + match);
case CONTACTS: {
setTablesAndProjectionMapForContacts(qb, uri, projection);
break;
}
return query(db, qb, projection, selection, selectionArgs, sortOrder, groupBy, limit);
}
private void setTablesAndProjectionMapForContacts(SQLiteQueryBuilder qb, Uri uri,
String[] projection) {
StringBuilder sb = new StringBuilder();
boolean excludeRestrictedData = false;
String requestingPackage = uri.getQueryParameter(
ContactsContract.REQUESTING_PACKAGE_PARAM_KEY);
if (requestingPackage != null) {
excludeRestrictedData = !mDbHelper.hasAccessToRestrictedData(requestingPackage);
}
sb.append(mDbHelper.getContactView(excludeRestrictedData));
if (mDbHelper.isInProjection(projection,
Contacts.CONTACT_PRESENCE)) {
sb.append(" LEFT OUTER JOIN " + Tables.AGGREGATED_PRESENCE +
" ON (" + Contacts._ID + " = " + AggregatedPresenceColumns.CONTACT_ID + ")");
}
if (mDbHelper.isInProjection(projection,
Contacts.CONTACT_STATUS,
Contacts.CONTACT_STATUS_RES_PACKAGE,
Contacts.CONTACT_STATUS_ICON,
Contacts.CONTACT_STATUS_LABEL,
Contacts.CONTACT_STATUS_TIMESTAMP)) {
sb.append(" LEFT OUTER JOIN " + Tables.STATUS_UPDATES + " "
+ ContactsStatusUpdatesColumns.ALIAS +
" ON (" + ContactsColumns.LAST_STATUS_UPDATE_ID + "="
+ ContactsStatusUpdatesColumns.CONCRETE_DATA_ID + ")");
}
qb.setTables(sb.toString());
qb.setProjectionMap(sContactsProjectionMap);
}
private Cursor query(final SQLiteDatabase db, SQLiteQueryBuilder qb, String[] projection,
String selection, String[] selectionArgs, String sortOrder, String groupBy,
String limit) {
Log.v(TAG, "query: selection=" + selection);
if (projection != null && projection.length == 1
&& BaseColumns._COUNT.equals(projection[0])) {
qb.setProjectionMap(sCountProjectionMap);
}
final Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, null,
sortOrder, limit);
if (c != null) {
c.setNotificationUri(getContext().getContentResolver(), ContactsContract.AUTHORITY_URI);
}
return c;
}
frameworks\base\core\java\android\database\sqlite\SQLiteQueryBuilder.java
public Cursor query(SQLiteDatabase db, String[] projectionIn,
String selection, String[] selectionArgs, String groupBy,
String having, String sortOrder) {
log(" query() sortOrder="+sortOrder+"<-wlq->");
return query(db, projectionIn, selection, selectionArgs, groupBy, having, sortOrder,
null /* limit */);
}
public Cursor query(SQLiteDatabase db, String[] projectionIn,
String selection, String[] selectionArgs, String groupBy,
String having, String sortOrder, String limit) {
log(" query1() <-wlq->");
if (mTables == null) {
return null;
}
String sql = buildQuery(
projectionIn, selection, selectionArgs, groupBy, having,
sortOrder, limit);
log(" query1() sql="+sql+"<-wlq->");
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Performing query: " + sql);
}
return db.rawQueryWithFactory(
mFactory, sql, selectionArgs,
SQLiteDatabase.findEditTable(mTables));
}
frameworks\base\core\java\android\database\sqlite\SQLiteDatabase.java
public Cursor rawQueryWithFactory(
CursorFactory cursorFactory, String sql, String[] selectionArgs,
String editTable) {
long timeStart = 0;
if (Config.LOGV || mSlowQueryThreshold != -1) {
timeStart = System.currentTimeMillis();
}
SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable);
Cursor cursor = null;
try {
cursor = driver.query(
cursorFactory != null ? cursorFactory : mFactory,
selectionArgs);
} finally {
if (Config.LOGV || mSlowQueryThreshold != -1) {
// Force query execution
if (cursor != null) {
cursor.moveToFirst();
cursor.moveToPosition(-1);
}
long duration = System.currentTimeMillis() - timeStart;
if (Config.LOGV || duration >= mSlowQueryThreshold) {
Log.v(SQLiteCursor.TAG,
"query (" + duration + " ms): " + driver.toString() + ", args are "
+ (selectionArgs != null
? TextUtils.join(",", selectionArgs)
: "<null>"));
}
}
}
return cursor;
}
frameworks\base\core\java\android\database\sqlite\ SQLiteDirectCursorDriver.java
public SQLiteDirectCursorDriver(SQLiteDatabase db, String sql, String editTable) {
mDatabase = db;
mEditTable = editTable;
//TODO remove all callers that end in ; and remove this check
if (sql.charAt(sql.length() - 1) == ';') {
Log.w(TAG, "Found SQL string that ends in ; -- " + sql);
sql = sql.substring(0, sql.length() - 1);
}
mSql = sql;
}
public Cursor query(CursorFactory factory, String[] selectionArgs) {
// Compile the query
SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, 0, selectionArgs);
try {
// Arg binding
int numArgs = selectionArgs == null ? 0 : selectionArgs.length;
for (int i = 0; i < numArgs; i++) {
query.bindString(i + 1, selectionArgs[i]);
}
// Create the cursor
if (factory == null) {
mCursor = new SQLiteCursor(mDatabase, 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();
}
}
frameworks\base\core\java\android\database\sqlite\ SQLiteQuery.java
/* package */ SQLiteQuery(SQLiteDatabase db, String query, int offsetIndex, String[] bindArgs) {
super(db, query);
mOffsetIndex = offsetIndex;
mQuery = query;
mBindArgs = bindArgs;
}
frameworks\base\core\java\android\database\sqlite\ SQLiteCursor.java
public SQLiteCursor(SQLiteDatabase db, SQLiteCursorDriver driver,
String editTable, SQLiteQuery query) {
// The AbstractCursor constructor needs to do some setup.
super();
if (SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION) {
mStackTraceElements = new Exception().getStackTrace();
}
mDatabase = db;
mDriver = driver;
mEditTable = editTable;
mColumnNameMap = null;
mQuery = query;
try {
db.lock();
// Setup the list of columns
int columnCount = mQuery.columnCountLocked();
mColumns = new String[columnCount];
// Read in all column names
for (int i = 0; i < columnCount; i++) {
String columnName = mQuery.columnNameLocked(i);
mColumns[i] = columnName;
if (Config.LOGV) {
Log.v("DatabaseWindow", "mColumns[" + i + "] is "
+ mColumns[i]);
}
// Make note of the row ID column index for quick access to it
if ("_id".equals(columnName)) {
mRowIdColumnIndex = i;
}
}
} finally {
db.unlock();
}
}