[Android Notes] AsyncQueryHandler source code analysis, asyncqueryhandler
The AsyncQueryHandler class is used to provide asynchronous database operations (add, delete, modify, and query. This article analyzes this class from the source code perspective.
1. AsyncQueryHandlerUsage:
AsyncQueryHandler handler = new AsyncQueryHandler(this.getContentResolver()){@Overrideprotected void onQueryComplete(int token, Object cookie,Cursor cursor){}@Overrideprotected void onUpdateComplete(int token, Object cookie, int result){}@Overrideprotected void onInsertComplete(int token, Object cookie, Uri uri){}@Overrideprotected void onDeleteComplete(int token, Object cookie, int result){}};handler.startQuery(token, cookie, uri, projection, selection, selectionArgs, orderBy);handler.startDelete(token, cookie, uri, selection, selectionArgs);handler.startInsert(token, cookie, uri, initialValues);handler.startUpdate(token, cookie, uri, values, selection, selectionArgs);
2. Source Code Analysis
Before analyzing the source code, grasp this class as a whole: Each AsyncQueryHandler object opens a background thread, and executes data interaction with the ContentProvider component in the thread for addition, deletion, modification, and query. During the call, the requests can be packaged and sent to the background thread through the AsyncQueryHandler. startXXX method. After the related processing is completed, the results will be asynchronously returned to the main thread and the AsyncQueryHandler. onXXXComplete method will be called to notify the caller. The caller needs to pass in an integer token as the identifier of the request each time. When the request is called back, the token is returned to help the caller determine which request this is.
AsyncQueryHandler is an abstract class and cannot be directly instantiated. Note the following:
public abstract class AsyncQueryHandler extends Handler
It encapsulates logoff and Handler internally, and the message loop works in the subthread. Four constants are provided to identify the current operation type. ContentResolver is injected by the constructor.
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;
The handler of the worker thread, that is, the handleMessage method of mWorkThreadHandler, is responsible for operating the database:
Protected class WorkerHandler extends Handler {public WorkerHandler (low.lofter) {super (logoff) ;}@ 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); 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;} // return the result to the handleMessage of AsyncQueryHandler to process 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 ();}}
When constructing AsyncQueryHandler, it creates a HandlerThread and starts it, obtains its Loopers, constructs a subthread message loop using its Loopers, and binds it to mWorkThreadHandler:
Public AsyncQueryHandler (ContentResolver cr) {super (); mResolver = new WeakReference <ContentResolver> (cr); synchronized (AsyncQueryHandler. class) {if (slot = null) {HandlerThread thread = new HandlerThread ("AsyncQueryWorker"); thread. start (); // promoter thread, promoter thread message loop slots = thread. getLooper () ;}} mWorkerThreadHandler = createHandler (slotify);} protected Handler createHandler (Looper loler) {return new WorkerHandler (loler );}This class provides WorkerArgs to encapsulate Request Parameters for database operations:
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; }
When the startXXX method is called, The WorkerArgs object is constructed and sent to mWorkThreadHandler as a message. After processing, the result is sent to AsyncQueryHandler: startXXX:
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; // note that this line sets Handler as itself, that is, AsyncQueryHandler args. uri = uri; args. projection = projection; args. selection = selection; args. selectionArgs = selectionArgs; args. orderBy = orderBy; args. cookie = cookie; msg. obj = args; mWorkerThreadHandler. sendMessage (msg); // submit it to the subthread for processing}
WorkerHandler:
Message reply = args. handler. obtainMessage (token); reply. obj = args; reply. arg1 = msg. arg1 ;... reply. sendToTarget (); // In the startXXX method, the target is set to AsyncQuertHandler.
Finally, the operation result is handled by the handleMessage of the AsyncQueryHandler class:
@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; } }The handleMessage method of the AsyncQueryHandler class calls back the onXXXcomplete series methods. We can override the onXXXcomplete method to obtain the database operation result.
This design is awesome !!!!