android_AsyncQueryHandler的理解_2011-10-26

本文沒有那麼多的廢話,直接看代碼:

此爲AsyncQueryHandler的構造方法

public AsyncQueryHandler(ContentResolver cr) {
        super();
        mResolver = new WeakReference<ContentResolver>(cr);
        synchronized (AsyncQueryHandler.class) {
            if (sLooper == null) {
                HandlerThread thread = new HandlerThread("AsyncQueryWorker");
                thread.start();
     //需要注意的是此getLooper()方法在HandlerThread類中是同步等待獲取run()方法中prepare()準備的線程相關的Looper對象,
    // 也就是說分線程準備好了looper以後,在此線程中纔可以得到
                sLooper = thread.getLooper();
            }
        }
        mWorkerThreadHandler = createHandler(sLooper);
    }


在AsyncQueryHandler構造中new出來 的HandlerThread繼承了Thread 在其的run方法中創建 了個Looper輪詢器,並阻塞調用.loop方法在那不停的輪詢這個內部開啓的工作線程的隊列.  在這內部開啓的線程中獲得了這個線程綁定的輪詢器., 用這個輪詢器創建了一個WorkerHandler的mWorkerThreadHandler變量的Handler ,

由於此Handler在創建時接收了這個開啓的線程的輪詢器 , 那這個Handler就相當於在這個線程中創建的,自然它的handeMessage方法將會運行在這個線程中執行,


這也就是這個AsyncQueryHandler的特別之處, 其中有兩個handleMessage方法 , 要記住:AsyncQueryHandler的handleMessage方法是主線程中運行的, 而WorkerThreadHandler的handleMessage方法是在構造方法中創建的一個線程中執行的, 只不過它的代碼被放到這個類中了. 爲什麼呢? 我看到這個handlerMessage方法的代碼中用到了ContentResolver對象,此對象是從UI主線程中傳過來的, 所以放在這不用傳給那個開啓的線程也是未嘗不可的.

在這個handleMessage中最終是將執行的結果cursor通過Message回覆到AsyncQueryHander這個類的handlerMessage中執行,在其中解析msg並根據event判斷操作類型(CRUD)來執行AsyncQueryHandler的回調方法.

所以我們在主線程中實現這個AsyncQueryHandler類的時候可以選擇性的重寫這四個protected修飾的on….Complete完成方法來做一些數據操作完成後的操作.

 

整個異步查詢的操作其時就是AsyncQueryHandler類內部的兩個handleMessage之間交互的過程.

入口就是start開頭的CRUD操作,在這些start方法中只是把參數用一個Message封裝起來調用那個構造中創建的子線程的輪詢器的Handler對象(mWorkerThreadHandler).的sendMessage()方法來發送的

WorkerHandler的handleMessage方法中收到解析執行這個用戶封裝的msg中的內容, 並將結果又返回給AsyncQueryHandler這個HandleMessage方法在其中回調用戶實現的on…Complete方法完成數據的後續處理.


以下爲部分源碼

 protected class WorkerHandler extends Handler {
        public WorkerHandler(Looper looper) {
            super(looper);  //看此處使用了looper
        }
    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;
                   //..............CRUD操作
args.result = cursor;
            }
            Message reply = args.handler.obtainMessage(token);///回覆msg
            reply.obj = args;
            reply.arg1 = msg.arg1;
            reply.sendToTarget();  //回覆
=============
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);//此處是向開啓的那個線程中的handler發送 消息
=====================
public class HandlerThread extends Thread {
  public void run() {
        mTid = Process.myTid();
        Looper.prepare();      //由於 不是在主線程中WorkerHandler中包含的這個Looper對象必須手動的調用prepare來準備好(另附:looper是線程本地化的)
        synchronized (this) {
            mLooper = Looper.myLooper();  //獲得當前線程的輪詢器
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();      ///阻塞 方法, 不斷的從隊列中取消息.
        mTid = -1;
    }


如有理解錯誤和不準確的地方,還請一定要回復...

發佈了18 篇原創文章 · 獲贊 1 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章