在一般的应用中可以使用ContentProvider去操作数据库。 这在数据量很小的时候是没有问题的,但是如果数据量大了,可能导致UI线程发生ANR异常(超过5秒)。 当然你也可以写个Handler去做这些操作,只是你每次使用ContentProvider时都要再写个Handler,必然降低了效率。 因此当数据量较大时,最好还是使用android已经封装好的异步查询框架AsyncQueryHandler,优化我们的代码.AsyncQueryHandler类封装了两个线程的交互过程。它们是调用者线程与工作线程。这两个线程里都维护着一个handler,通过提供onXXXComplete的回调接口,实现事件的完成处理。在处理读取联系人、通话记录相关,也解决的部分山寨手机兼容问题。
自定义MyQueryHandler继承AsyncQueryHandler 实现里面的两个方法,构造方法和onQueryComplete方法
private class MyAsyncQueryHandler extends AsyncQueryHandler { public MyAsyncQueryHandler(ContentResolver cr) { super(cr); } @Override public void startQuery(int tag, Object cookie, Uri uri, String[] projection, String selection, String[] selectionArgs, String orderBy) { super.startQuery(tag, cookie, uri, projection, selection, selectionArgs, orderBy); Log.e("TAG", "startQuery"); } protected void onQueryComplete(final int tag, final Object cookie, final Cursor cursor) { Log.e("TAG", "onQueryComplete"); super.onQueryComplete(tag, cookie, cursor); } } }一般开始调用的方法: myAsyncQueryHandler.startQuery(token, cookie, uri, projection, selection, selectionArgs, orderBy);
以上方法参数:
token 令牌,主要用来标识查询,保证唯一
cookie 你想传给onXXXComplete方法使用的一个对象。(没有的话传递null即可)
Uri uri(进行查询的通用资源标志符):
projection 查询的列
selection 限制条件
selectionArgs 查询参数
orderBy 排序条件
参考代码:
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI; // 联系人Uri; // 查询的字段 String[] projection = { ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.DATA1, "sort_key", ContactsContract.CommonDataKinds.Phone.CONTACT_ID, ContactsContract.CommonDataKinds.Phone.PHOTO_ID, ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY }; // 按照sort_key升序查詢 asyncQueryHandler.startQuery(tag, cookie, uri, projection, null, null, "sort_key COLLATE LOCALIZED asc");从整体上把握这个类:每个AsyncQueryHandler对象都会开启一个后台线程,在线程中执行与ContentProvider组件的数据交互,进行增删改查。调用时,可以通过AsyncQueryHandler.startXXX系列方法将请求打包发送到后台线程,当相关处理完成后,会将结果异步回传给主线程并调用AsyncQueryHandler.onXXXComplete方法通知调用者。调用者每次请求时,需要传入一个整型值token作为这次请求的标识,当该请求完成后进行回调时,会将token传回,帮助调用者确定这是哪一次请求。参考博文图
源码如下:
public abstract class AsyncQueryHandler extends Handler { private static final String TAG = "AsyncQuery"; private static final boolean localLOGV = false; private static final int EVENT_ARG_QUERY = 1; private static final int EVENT_ARG_INSERT = 2; private static final int EVENT_ARG_UPDATE = 3; private static final int EVENT_ARG_DELETE = 4; /* package */ final WeakReference<ContentResolver> mResolver; private static Looper sLooper = null; private Handler mWorkerThreadHandler; protected static final class WorkerArgs { public Uri uri; public Handler handler; public String[] projection; public String selection; public String[] selectionArgs; public String orderBy; public Object result; public Object cookie; public ContentValues values; } protected class WorkerHandler extends Handler { public WorkerHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { final ContentResolver resolver = mResolver.get(); if (resolver == null) return; WorkerArgs args = (WorkerArgs) msg.obj; int token = msg.what; int event = msg.arg1; switch (event) { case EVENT_ARG_QUERY: Cursor cursor; try { cursor = resolver.query(args.uri, args.projection, args.selection, args.selectionArgs, args.orderBy); // Calling getCount() causes the cursor window to be filled, // which will make the first access on the main thread a lot faster. if (cursor != null) { cursor.getCount(); } } catch (Exception e) { Log.w(TAG, "Exception thrown during handling EVENT_ARG_QUERY", e); cursor = null; } args.result = cursor; break; case EVENT_ARG_INSERT: args.result = resolver.insert(args.uri, args.values); break; case EVENT_ARG_UPDATE: args.result = resolver.update(args.uri, args.values, args.selection, args.selectionArgs); break; case EVENT_ARG_DELETE: args.result = resolver.delete(args.uri, args.selection, args.selectionArgs); break; } // passing the original token value back to the caller // on top of the event values in arg1. Message reply = args.handler.obtainMessage(token); reply.obj = args; reply.arg1 = msg.arg1; if (localLOGV) { Log.d(TAG, "WorkerHandler.handleMsg: msg.arg1=" + msg.arg1 + ", reply.what=" + reply.what); } reply.sendToTarget(); } } public AsyncQueryHandler(ContentResolver cr) { super(); mResolver = new WeakReference<ContentResolver>(cr); synchronized (AsyncQueryHandler.class) { if (sLooper == null) { HandlerThread thread = new HandlerThread("AsyncQueryWorker"); thread.start(); sLooper = thread.getLooper(); } } mWorkerThreadHandler = createHandler(sLooper); } protected Handler createHandler(Looper looper) { return new WorkerHandler(looper); } /** * This method begins an asynchronous query. When the query is done * {@link #onQueryComplete} is called. * * @param token A token passed into {@link #onQueryComplete} to identify * the query. * @param cookie An object that gets passed into {@link #onQueryComplete} * @param uri The URI, using the content:// scheme, for the content to * retrieve. * @param projection A list of which columns to return. Passing null will * return all columns, which is discouraged to prevent reading data * from storage that isn't going to be used. * @param selection A filter declaring which rows to return, formatted as an * SQL WHERE clause (excluding the WHERE itself). Passing null will * return all rows for the given URI. * @param selectionArgs You may include ?s in selection, which will be * replaced by the values from selectionArgs, in the order that they * appear in the selection. The values will be bound as Strings. * @param orderBy How to order the rows, formatted as an SQL ORDER BY * clause (excluding the ORDER BY itself). Passing null will use the * default sort order, which may be unordered. */ public void startQuery(int token, Object cookie, Uri uri, String[] projection, String selection, String[] selectionArgs, String orderBy) { // 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); } /** * Attempts to cancel operation that has not already started. Note that * there is no guarantee that the operation will be canceled. They still may * result in a call to on[Query/Insert/Update/Delete]Complete after this * call has completed. * * @param token The token representing the operation to be canceled. * If multiple operations have the same token they will all be canceled. */ public final void cancelOperation(int token) { mWorkerThreadHandler.removeMessages(token); } /** * This method begins an asynchronous insert. When the insert operation is * done {@link #onInsertComplete} is called. * * @param token A token passed into {@link #onInsertComplete} to identify * the insert operation. * @param cookie An object that gets passed into {@link #onInsertComplete} * @param uri the Uri passed to the insert operation. * @param initialValues the ContentValues parameter passed to the insert operation. */ public final void startInsert(int token, Object cookie, Uri uri, ContentValues initialValues) { // Use the token as what so cancelOperations works properly Message msg = mWorkerThreadHandler.obtainMessage(token); msg.arg1 = EVENT_ARG_INSERT; WorkerArgs args = new WorkerArgs(); args.handler = this; args.uri = uri; args.cookie = cookie; args.values = initialValues; msg.obj = args; mWorkerThreadHandler.sendMessage(msg); } /** * This method begins an asynchronous update. When the update operation is * done {@link #onUpdateComplete} is called. * * @param token A token passed into {@link #onUpdateComplete} to identify * the update operation. * @param cookie An object that gets passed into {@link #onUpdateComplete} * @param uri the Uri passed to the update operation. * @param values the ContentValues parameter passed to the update operation. */ public final void startUpdate(int token, Object cookie, Uri uri, ContentValues values, String selection, String[] selectionArgs) { // Use the token as what so cancelOperations works properly Message msg = mWorkerThreadHandler.obtainMessage(token); msg.arg1 = EVENT_ARG_UPDATE; WorkerArgs args = new WorkerArgs(); args.handler = this; args.uri = uri; args.cookie = cookie; args.values = values; args.selection = selection; args.selectionArgs = selectionArgs; msg.obj = args; mWorkerThreadHandler.sendMessage(msg); } /** * This method begins an asynchronous delete. When the delete operation is * done {@link #onDeleteComplete} is called. * * @param token A token passed into {@link #onDeleteComplete} to identify * the delete operation. * @param cookie An object that gets passed into {@link #onDeleteComplete} * @param uri the Uri passed to the delete operation. * @param selection the where clause. */ public final void startDelete(int token, Object cookie, Uri uri, String selection, String[] selectionArgs) { // Use the token as what so cancelOperations works properly Message msg = mWorkerThreadHandler.obtainMessage(token); msg.arg1 = EVENT_ARG_DELETE; WorkerArgs args = new WorkerArgs(); args.handler = this; args.uri = uri; args.cookie = cookie; args.selection = selection; args.selectionArgs = selectionArgs; msg.obj = args; mWorkerThreadHandler.sendMessage(msg); } /** * Called when an asynchronous query is completed. * * @param token the token to identify the query, passed in from * {@link #startQuery}. * @param cookie the cookie object passed in from {@link #startQuery}. * @param cursor The cursor holding the results from the query. */ protected void onQueryComplete(int token, Object cookie, Cursor cursor) { // Empty } /** * Called when an asynchronous insert is completed. * * @param token the token to identify the query, passed in from * {@link #startInsert}. * @param cookie the cookie object that's passed in from * {@link #startInsert}. * @param uri the uri returned from the insert operation. */ protected void onInsertComplete(int token, Object cookie, Uri uri) { // Empty } /** * Called when an asynchronous update is completed. * * @param token the token to identify the query, passed in from * {@link #startUpdate}. * @param cookie the cookie object that's passed in from * {@link #startUpdate}. * @param result the result returned from the update operation */ protected void onUpdateComplete(int token, Object cookie, int result) { // Empty } /** * Called when an asynchronous delete is completed. * * @param token the token to identify the query, passed in from * {@link #startDelete}. * @param cookie the cookie object that's passed in from * {@link #startDelete}. * @param result the result returned from the delete operation */ protected void onDeleteComplete(int token, Object cookie, int result) { // Empty } @Override public void handleMessage(Message msg) { WorkerArgs args = (WorkerArgs) msg.obj; if (localLOGV) { Log.d(TAG, "AsyncQueryHandler.handleMessage: msg.what=" + msg.what + ", msg.arg1=" + msg.arg1); } int token = msg.what; int event = msg.arg1; // pass token back to caller on each callback. switch (event) { case EVENT_ARG_QUERY: onQueryComplete(token, args.cookie, (Cursor) args.result); break; case EVENT_ARG_INSERT: onInsertComplete(token, args.cookie, (Uri) args.result); break; case EVENT_ARG_UPDATE: onUpdateComplete(token, args.cookie, (Integer) args.result); break; case EVENT_ARG_DELETE: onDeleteComplete(token, args.cookie, (Integer) args.result); break; } } }值得注意的是AsyncQueryHandler是个抽象类,不能直接被实例化;
争取每日把之前印象笔记中的碎片点,总结出来分享给各位大佬,相互督促相互学习进步,欢迎各位老铁留言……