AsyncQueryHandler是Handler的子类,文档上说,如果处理ContentProvider相关的内容,不用需要自行定义一套东西, 而可以简单的使用async方式。我想指代的就应该是AsyncQueryHandler类。该类是一个典型的模板类,为ContentProvider 的增删改查提供了很好的接口,提供了一个解决架构,final了一些方法,置空了一些方法。通过派生,实例化一些方法(不是每个对 ContentProvider的处理多需要全部做增删改查,我想这也是该类默认置空一些方法而不是抽象一些方法的原因),来达到这个目的。在内部,该类 隐藏了多线程处理的细节,当你使用时,你会感觉异常便利。
1. 当你实例化一个AsyncQueryHandler类时(包括其子类...),它会单件构造一个线程(后面会详述...),这个线程里面会构建一个消息循环。
2. 获得该消息循环的指针,用它做参数实例化另一个Handler类,该类为内部类。至此,就有了两个线程,各自有一个Handler来处理消息。
3. 当调用onXXX的时候,在XXX函数内部会将请求封装成一个内部的参数类,将其作为消息的参数,将此消息发送至另一个线程。
4. 在该线程的Handler中,接受该消息,并分析传入的参数,用初始化时传入的ContentResolver进行XXX操作,并返回Cursor或其他返回值。
5. 构造一个消息,将上述返回值以及其他相关内容绑定在该消息上,发送回主线程。
6. 主线程默认的AsyncQueryHandler类的handleMessage方法(可自定义,但由于都是内部类,基本没有意义...)会分析该消息,并转发给对应的onXXXComplete方法。
7. 用户重写的onXXXComplete方法开始工作。
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.example.testasyncqueryhandler;
import android.database.AbstractCursor;
import android.database.CursorIndexOutOfBoundsException;
/**
* A cursor that is empty.
* <p>
* If you want an empty cursor, this class is better than a MatrixCursor because it has less
* overhead.
*/
final public class EmptyCursor extends AbstractCursor {
private String[] mColumns;
public EmptyCursor(String[] columns) {
this.mColumns = columns;
}
@Override
public int getCount() {
return 0;
}
@Override
public String[] getColumnNames() {
return mColumns;
}
@Override
public String getString(int column) {
throw cursorException();
}
@Override
public short getShort(int column) {
throw cursorException();
}
@Override
public int getInt(int column) {
throw cursorException();
}
@Override
public long getLong(int column) {
throw cursorException();
}
@Override
public float getFloat(int column) {
throw cursorException();
}
@Override
public double getDouble(int column) {
throw cursorException();
}
@Override
public boolean isNull(int column) {
throw cursorException();
}
private CursorIndexOutOfBoundsException cursorException() {
return new CursorIndexOutOfBoundsException("Operation not permitted on an empty cursor.");
}
}
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.testasyncqueryhandler;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabaseCorruptException;
import android.database.sqlite.SQLiteDiskIOException;
import android.database.sqlite.SQLiteFullException;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.provider.CallLog.Calls;
import android.util.Log;
import java.lang.ref.WeakReference;
/** Handles asynchronous queries to the call log. */
public class CallLogQueryHandler extends NoNullCursorAsyncQueryHandler {
private static final String TAG = "CallLogQueryHandler";
private static final int QUERY_CALLLOG_TOKEN = 0;
private static final int QUERY_VOICEMAIL_STATUS_TOKEN = 2;
private final WeakReference<Listener> mListener;
private Cursor mCallLogCursor;
protected class CatchingWorkerHandler extends
AsyncQueryHandler.WorkerHandler {
/**
* catch the exception and print it
*
* @param looper
*/
public CatchingWorkerHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
try {
// Perform same query while catching any exceptions
super.handleMessage(msg);
} catch (SQLiteDiskIOException e) {
Log.w(TAG, "Exception on background worker thread", e);
} catch (SQLiteFullException e) {
Log.w(TAG, "Exception on background worker thread", e);
} catch (SQLiteDatabaseCorruptException e) {
Log.w(TAG, "Exception on background worker thread", e);
}
}
}
/**
* call the insertTheData to insert the database
*
* @param token
* @param cookie
* @param uri
* @param initialValues
*/
public void insertTheData(int token, int cookie, Uri uri,
ContentValues initialValues) {
startInsert(token, cookie, uri, initialValues);
}
/**
* delete the data from the database
*
* @param token
* @param cookie
* @param uri
* @param selection
* @param selectionArgs
*/
public void deleteTheData(int token, Object cookie, Uri uri,
String selection, String[] selectionArgs) {
startDelete(token, cookie, uri, selection, selectionArgs);
}
/**
* update the data from the database
*
* @param token
* @param cookie
* @param uri
* @param values
* @param selection
* @param selectionArgs
*/
public void updateData(int token, Object cookie, Uri uri,
ContentValues values, String selection, String[] selectionArgs) {
startUpdate(token, cookie, uri, values, selection, selectionArgs);
}
/**
* query the data from the database;
*
* @param token
* @param requestId
* @param callType
* @param showType
* @param newOnly
* @param newerThan
* @param context
*/
private void startQueryData(int token, int requestId, int callType,
int showType, boolean newOnly, long newerThan, Context context) {
startQuery(token, requestId, null, null, null, null,
Calls.DEFAULT_SORT_ORDER);
}
@Override
protected Handler createHandler(Looper looper) {
// Provide our special handler that catches exceptions
return new CatchingWorkerHandler(looper);
}
public CallLogQueryHandler(ContentResolver contentResolver,
Listener listener) {
this(contentResolver, listener, -1);
}
/**
* construct the handler class
* @param contentResolver
* @param listener
* @param limit
*/
public CallLogQueryHandler(ContentResolver contentResolver,
Listener listener, int limit) {
super(contentResolver);
mListener = new WeakReference<Listener>(listener);
}
@Override
protected void onNotNullableQueryComplete(int token, Object cookie,
Cursor cursor) {
Log.d(TAG, "token==" + token + "cookie==" + cookie);
if (token == QUERY_CALLLOG_TOKEN) {
} else if (token == QUERY_VOICEMAIL_STATUS_TOKEN) {
updateVoicemailStatus(cursor);
return;
} else {
updateVoicemailStatus(cursor);
}
if (mCallLogCursor != null) {
updateAdapterData(mCallLogCursor);
mCallLogCursor = null;
}
}
/**
* Updates the adapter in the call log fragment to show the new cursor data.
*/
private void updateAdapterData(Cursor combinedCursor) {
final Listener listener = mListener.get();
if (listener != null) {
listener.onCallsFetched(combinedCursor);
}
}
private void updateVoicemailStatus(Cursor statusCursor) {
final Listener listener = mListener.get();
if (listener != null) {
listener.onVoicemailStatusFetched(statusCursor);
}
}
/** Listener to completion of various queries. */
public interface Listener {
/**
* Called when {@link CallLogQueryHandler#fetchVoicemailStatus()}
* completes.
*/
void onVoicemailStatusFetched(Cursor statusCursor);
/**
* Called when {@link CallLogQueryHandler#fetchCalls(int)}complete.
*/
void onCallsFetched(Cursor combinedCursor);
}
}
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.example.testasyncqueryhandler;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
public abstract class NoNullCursorAsyncQueryHandler extends AsyncQueryHandler {
public NoNullCursorAsyncQueryHandler(ContentResolver cr) {
super(cr);
}
@Override
public void startQuery(int token, Object cookie, Uri uri,
String[] projection, String selection, String[] selectionArgs,
String orderBy) {
final CookieWithProjection projectionCookie = new CookieWithProjection(
cookie, projection);
super.startQuery(token, projectionCookie, uri, projection, selection,
selectionArgs, orderBy);
}
@Override
protected final void onQueryComplete(int token, Object cookie, Cursor cursor) {
CookieWithProjection projectionCookie = (CookieWithProjection) cookie;
super.onQueryComplete(token, projectionCookie.originalCookie, cursor);
if (cursor == null) {
cursor = new EmptyCursor(projectionCookie.projection);
}
onNotNullableQueryComplete(token, projectionCookie.originalCookie,
cursor);
}
protected abstract void onNotNullableQueryComplete(int token,
Object cookie, Cursor cursor);
/**
* Class to add projection to an existing cookie.
*/
private static class CookieWithProjection {
public final Object originalCookie;
public final String[] projection;
public CookieWithProjection(Object cookie, String[] projection) {
this.originalCookie = cookie;
this.projection = projection;
}
}
}