Android O: AsyncQueryHandler分析

本篇博客以Android O的代码为例,分析一下AsyncQueryHandler这个类。
AsyncQueryHandler是用于在ContentProvider上执行异步操作的工具类。


我们直接来看看源码:

/**
 * A helper class to help make handling asynchronous {@link ContentResolver}
 * queries easier.
 */
//AsyncQueryHandler是一个抽象类
//使用时需要创建一个继承它的类,实现对应的回调接口,后文详述
public abstract class AsyncQueryHandler extends Handler {
    ............
    //弱引用
    final WeakReference<ContentResolver> mResolver;

    //静态的Looper
    private static Looper sLooper = null;

    private Handler mWorkerThreadHandler;
    .............
    //构造函数
    public AsyncQueryHandler(ContentResolver cr) {
        super();
        //弱引用传入的ContentResolver
        mResolver = new WeakReference<ContentResolver>(cr);

        //单例持有一个HandlerThread的looper
        synchronized (AsyncQueryHandler.class) {
            if (sLooper == null) {
                HandlerThread thread = new HandlerThread("AsyncQueryWorker");
                thread.start();

                sLooper = thread.getLooper();
            }
        }
        //创建WorkHandler
        mWorkerThreadHandler = createHandler(sLooper);
    }

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

从上面的代码可以看出,AsyncQueryHandler的多个子类
将共用同一个HandlerThread处理任务。

AsyncQueryHandler提供了数据库基本的增删改查接口,
实现方式基本类似,我们以Query为例,看看具体的代码:

    //token用于标记一个具体的请求
    //其它参数就是查询数据库的操作
    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是保存数据的内部类
        WorkerArgs args = new WorkerArgs();

        //保存AysncQueryHandler的子类
        args.handler = this;
        args.uri = uri;
        args.projection = projection;
        args.selection = selection;
        args.selectionArgs = selectionArgs;
        args.orderBy = orderBy;
        args.cookie = cookie;
        msg.obj = args;

        //WorkHandler进行实际的处理
        mWorkerThreadHandler.sendMessage(msg);
    }

我们来看看WorkHandler的实现:

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;
                }

                //实际的cursor写入返回的参数
                args.result = cursor;
                break;
            //处理其它case
            ...........
        }

        // passing the original token value back to the caller
        // on top of the event values in arg1.
        // 这个复用message还是做的蛮到位的.....
        Message reply = args.handler.obtainMessage(token);
        reply.obj = args;
        reply.arg1 = msg.arg1;
        ......
        //返回消息给AsyncQueryHandler的子类
        reply.sendToTarget();
    }
}

从上面的代码容易看出,当WorkHandler处理完毕消息后,
就会将数据返回给AsyncQueryHandler的子类,
于是handleMessage接口将被调用:

@Override
public void handleMessage(Message msg) {
    WorkerArgs args = (WorkerArgs) msg.obj;
    .............
    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;
        .........
    }
}

onQueryComplete由子类自行实现

protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
    // Empty
}

至此AsyncQueryHandler的工作流程分析完毕。

容易看出,AsyncQueryHandler通过Handler机制,将ContentProvider对应的CRUD操作放到一个单独的子线程中执行,
当操作结束获取到结果后,再通过消息的方式传递给调用AsyncQueryHandler的线程。
它提供了一种将并发访问变为顺序异步访问的思路。

不过AsyncQueryHandler静态持有了一个HandlerThread,
且没有提供方法来释放该HandlerThread,
因此实际使用时可能需要自己仿照来重写一下。

最后盗图一张,给一下AsyncQueryHandler的原理图:

猜你喜欢

转载自blog.csdn.net/gaugamela/article/details/79755422