【安卓筆記】AsyncQueryHandler源碼剖析,asyncqueryhandler
AsyncQueryHandler類用於提供非同步資料庫操作(增刪改查)功能。本文視圖從源碼角度分析這個類。
1.AsyncQueryHandler使用方式:
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.源碼分析
分析源碼前,從整體上把握這個類:每個AsyncQueryHandler對象都會開啟一個後台線程,線上程中執行與ContentProvider組件的資料互動,進行增刪改查。調用時,可以通過AsyncQueryHandler.startXXX系列方法將請求打包發送到後台線程,當相關處理完成後,會將結果非同步回傳給主線程並調用AsyncQueryHandler.onXXXComplete方法通知調用者。調用者每次請求時,需要傳入一個整型值token作為這次請求的標識,當該請求完成後進行回調時,會將token傳回,協助調用者確定這是哪一次請求。
AsyncQueryHandler是個抽象類別,不能直接被執行個體化,這點需要注意:
public abstract class AsyncQueryHandler extends Handler
其內部封裝了Looper和Handler,這個訊息迴圈工作在子線程。另提供4個常量標識當前操作類型。ContentResolver由構造器注入。
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;
背景工作執行緒的handler,即mWorkThreadHandler的handleMessage方法負責操作資料庫:
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); 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; } //將結果返回給AsyncQueryHandler的handleMessage處理 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(); } }
AsyncQueryHandler在構造的時候,會建立一個HandlerThread,start之,然後擷取其Looper,並利用其Looper構建子線程訊息迴圈,並與mWorkThreadHandler綁定:
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); }這個類提供了WorkerArgs封裝資料庫操作的請求參數:
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; }
當外界調用startXXX方法時,其實會構造WorkerArgs對象,然後將這個對象以訊息的形式發送給mWorkThreadHandler ,處理完成後將結果發送給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;//注意這行制定了Handler為本身,即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);//交給子線程處理 }
WorkerHandler:
Message reply = args.handler.obtainMessage(token); reply.obj = args; reply.arg1 = msg.arg1; ... reply.sendToTarget();//在startXXX方法中已經制定了target為AsyncQuertHandler本身
最終,操作結果交由AsyncQueryHandler類的handleMessage處理:
@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類的handleMessage方法回調了onXXXcomplete系列方法。我們重寫onXXXcomplete方法即可拿到資料庫操作結果。
這個設計太贊了!!!!