HandlerThread与AsyncQueryHandler源码分析

大黑 2019-06-21

HandlerThread与AsyncQueryHandler源码分析


1. HandlerThread

HandlerThread继承自Thread,其本质还是一个Thread子类,只不过它内部封装了一个Looper,可以进行消息轮询,实现主线程向子线程发送消息,子线程根据消息类型执行相应代码,主要是耗时操作,如访问IO、查询数据库,但不建议进行网络请求,因为子线程中的消息是串行执行,访问网络较为耗时,因此HandlerThread适合处理耗时较短的任务。

1.1 HandlerThread源码分析

HandlerThread的内容并不多

package android.os;

public class HandlerThread extends Thread {
    int mPriority;//线程优先级
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
    //初始化Looper后,在开启loop循环前进行一些准备工作
    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();//给当前线程创建Looper
        synchronized (this) {
            mLooper = Looper.myLooper();//将当前线程的Looper传给mLooper变量
            notifyAll();
        }
        Process.setThreadPriority(mPriority);//设置线程优先级
        onLooperPrepared();
        Looper.loop();//开启消息循环
        mTid = -1;
    }

HandlerThread类中包含一个Looper对象mLooper,这个Looper对象在run方法中初始化,loop()开启后,不断的循环从MessageQueue中取出消息处理,当没有消息的时候会阻塞,有消息的到来的时候会唤醒。

public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

getLooper方法返回当前线程创建的Looper对象,若调用该方法时Looper还未创建,则一直等待直到Looper创建完毕。

当HandlerThread使用完后,需要让线程内的Looper退出循环

public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
    
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }

1.2 HandlerThread用法

HandlerThread handlerThread = new HandlerThread("subThread");
handlerThread.start();//开启子线程,同时也开启了子线程内消息循环
Looper looper = handlerThread.getLooper();//获取HandlerThread中的Looper
Handler handler = new Handler(looper){ //初始化Handler,与子线程Looper绑定
            @Override
            public void handleMessage(Message msg){
                //在子线程中执行
            }
};

2. AsyncQueryHandler

AsyncQueryHandler是一个异步查询操作帮助类,封装了HandlerThread和ContentResolver,可以方便地将耗时操作放在子线程中执行,并将执行结果回传至主线程中处理。

2.1 AsyncQueryHandler源码分析

AsyncQueryHandler继承了Handler,但是他提供的构造方法中却没有Looper参数,也就是说它与其所在的当前线程的looper绑定
AsyncQueryHandler构造方法:

public AsyncQueryHandler(ContentResolver cr) {
        super();//在父类构造方法中绑定了looper
        mResolver = new WeakReference<ContentResolver>(cr);
        synchronized (AsyncQueryHandler.class) {
            if (sLooper == null) {
                //创建HandlerThread,用于执行耗时的操作
                HandlerThread thread = new HandlerThread("AsyncQueryWorker");
                thread.start();

                sLooper = thread.getLooper();
            }
        }
        //创建工作线程的Handler对象
        mWorkerThreadHandler = createHandler(sLooper);
    }

    protected Handler createHandler(Looper looper) {
        return new WorkerHandler(looper);
    }

AsyncQueryHandler的构造方法中传入ContentResolver参数,然后创建一个对应的弱引用对象mResolver。
同时,创建了一个HandlerThread线程并开启,初始化了mWorkerThreadHandler对象并与HandlerThread线程的looper进行绑定。mWorkerThreadHandler是一个WorkerHandler类的对象,下面看WorkerHandler类:

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;//可理解为消息的ID
            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();
        }
    }

WorkerHandler类是AsyncQueryhandler的内部类,继承了Handler,它的构造函数中传入looper作为参数,与之绑定。由上可知,实例化的WorkerHandler对象是mWorkerThreadHandler,它与HandlerThread的looper绑定,因此其handleMessage方法会在子线程中执行,处理耗时的操作

在handleMessage方法中,首先获取到mResolver对象,然后从消息中获取到WorkerArgs对象、event和token。

  • event:消息类型,AsyncQueryhandler中定义了四种消息类型,分别对应增删查改的四种操作

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;
  • token: 我理解为消息的ID,比如查询操作可能有很多次,每次都是发送不同的消息,因此要标识其ID,这在AsyncQueryhandler暴露的增删查改方法中也需要作为参数传入。当要取消某个操作时,执行cancelOperation方法,传入的参数就是token

public final void cancelOperation(int token) {
        mWorkerThreadHandler.removeMessages(token);
    }
  • 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;
    }

然后判断消息类型,跟据消息类型,进行相应的操作,以查询为例:

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;

就是基本的查询操作,将查询的结果保存在args.result,最后:

Message reply = args.handler.obtainMessage(token);
            reply.obj = args;
            reply.arg1 = msg.arg1;

            reply.sendToTarget();

注意:这里将带有操作结果的args对象封装入一个message中,这个message的handler是args中保存的handler,然后将这个消息发送出去。

那么,WorkerHandler类中handleMessage方法的消息从何处发来的?reply这个消息又将发向哪里?

handleMessage方法中的消息是主线程执行操作时发送的,这里以查询为例,在AsyncQueryHandler类中:

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;//指向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);
    }

这里开启异步查询操作,首先获取一个消息,这个消息将携带查询操作所需的各种参数,这些参数被封装在WorkerArgs中,这个消息将被发送到工作线程(子线程)中的MessageQueue,等待被执行,因此,子线程HandlerThread将会接收到这个消息,所以该消息的handler对象为mWorkerThreadHandler。

注意,在构造args对象后,args.handler = this 将args对象的handler指向了AsyncQueryHandler对象,因此,在WorkerHandler的handleMessage方法中:

Message reply = args.handler.obtainMessage(token);
            reply.obj = args;
            reply.arg1 = msg.arg1;

            reply.sendToTarget();

这个reply消息将会发送到AsyncQueryHandler对象的handleMessage方法中,也就是将查询结果发送到主线程中的handleMessage方法中。
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;
        }
    }
}

子线程的消息发送到该handleMessage方法中,然后根据消息中的操作结果执行相应的代码。这样整个异步查询流程就完成了。

2.2 AsyncQueryHandler用法

QueryHandler handler = new QueryHandler(getContentResolver());//创建异步查询对象
//开启查询,传入查询参数
handler.startQuery(token, cookie, uri, projection, selection, selectionArgs, String orderBy)

//自定义AsyncQueryHandler类
private final class QueryHandler extends AsyncQueryHandler{

        public QueryHandler(ContentResolver cr) {
            super(cr);
            //do something
        }
        
        //查询完毕后将结果后回传至此方法
        @Override
        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
            //do something
        }
    }

3. 总结

AsyncQueryHandler是一个Handler,其内部还有一个Handler类WorkerHandler

AsyncQueryHandler:与创建它的线程(调用线程)的looper绑定
AsyncQueryHandler.handleMessage:处理子线程发来的消息,消息携带操作结果

WorkerHandler:与HandlerThread线程(工作线程)的looper绑定
AsyncQueryHandler.handleMessage:接收主线程发送的增删查改消息,并执行,将结果消息发送至主线程。

相关推荐