【安卓笔记】AsyncQueryHandler源码剖析

AsyncQueryHandler类用于提供异步数据库操作(增删改查)功能。本文视图从源码角度分析这个类。

1.AsyncQueryHandler使用方式:

AsyncQueryHandler handler = new AsyncQueryHandler(this.getContentResolver())
		{
			@Override
			protected void onQueryComplete(int token, Object cookie,Cursor cursor)
			{
			}
			@Override
			protected void onUpdateComplete(int token, Object cookie, int result)
			{
			}
			@Override
			protected void onInsertComplete(int token, Object cookie, Uri uri)
			{
			}
			@Override
			protected 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方法即可拿到数据库操作结果。

这个设计太赞了!!!!

时间: 2024-10-12 09:11:28

【安卓笔记】AsyncQueryHandler源码剖析的相关文章

【安卓笔记】HandlerThread源码剖析

有时候我们需要在应用程序中创建一些常驻的子线程不定期地执行一些计算型任务,这时候可以考虑使用HandlerThread,它具有创建带消息循环的子线程的作用. 一.HanderThread使用示例 先熟悉下HandlerThread的一般用法.我们创建一个如下所示的Activity: package com.example.handlethreaddemo; import android.app.Activity; import android.os.Bundle; import android.

【安卓笔记】IntentService源码剖析

Service组件想必都不陌生,这里不费口舌了.强调一点,Service组件默认运行在UI线程,所以也是会阻塞主线程的,使用时切记不可在Service中执行耗时操作,而应该创建子线程,异步执行. IntentService类封装了在Service中创建子线程的工作(其实创建的是HandlerThread),我们只需继承IntentService,复写其onHandleIntent方法即可,onHandleIntent方法在子线程中运行,该方法的参数Intent来自onStart或者onStart

《STL源码剖析》---stl_pair.h阅读笔记

pair是STL中的模板类型,它可以存储两个元素,它也被称作"对组".在map中已经用到了它,pair其实就是一个struct结构,存有两个public的元素,重载了几个运算符,没有什么成员函数,源代码很简单. G++ 2.91.57,cygnus\cygwin-b20\include\g++\stl_pair.h 完整列表 /* * * Copyright (c) 1994 * Hewlett-Packard Company * * Permission to use, copy,

《STL源码剖析》---stl_tree.h阅读笔记

STL中,关联式容器的内部结构是一颗平衡二叉树,以便获得良好的搜索效率.红黑树是平衡二叉树的一种,它不像AVL树那样要求绝对平衡,降低了对旋转的要求,但是其性能并没有下降很多,它的搜索.插入.删除都能以O(nlogn)时间完成.平衡可以在一次或者两次旋转解决,是"性价比"很高的平衡二叉树. RB-tree(red black tree)红黑树是平衡二叉树.它满足一下规则 (1)每个节点不是红色就是黑色. (2)根节点是黑色. (3)如果节点为红色,则其子节点比为黑色. (4)任何一个节

《STL源码剖析》---stl_iterator.h阅读笔记

STL设计的中心思想是将容器(container)和算法(algorithm)分开,迭代器是容器(container)和算法(algorithm)之间的桥梁. 迭代器可以如下定义:提供一种方法,能够依序寻访某个容器内的所有元素,而又无需暴露该容器的内部表达方式. 在阅读代码之前,要先了解一个新概念:Traits编程技法 template <class T> struct MyIter { typedef T value_type //内嵌型别声明 T *ptr; MyIter(T *p = 0

《python源码剖析》笔记 Python虚拟机框架

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1. Python虚拟机会从编译得到的PyCodeObject对象中依次读入每一条字节码指令, 并在当前的上下文环境中执行这条字节码指令. Python虚拟机实际上是在模拟操作中执行文件的过程 PyCodeObject对象中包含了字节码指令以及程序的所有静态信息,但没有包含 程序运行时的动态信息--执行环境(PyFrameObject) 2.Python源码中的PyFrameObject

《python源码剖析》笔记 python虚拟机中的一般表达式

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1.字节码指令 LOAD_CONST:从consts表中读取序号为i的元素并压入到运行时栈中 STORE_NAME:改变local名字空间.从符号表names取序号为i的元素作为变量名, 取运行时栈的栈顶元素作为变量值,完成从变量名到变量值的映射关系的创建. BUILD_MAP:创建一个空的PyDictObject对象,并压入运行时栈 DUP_TOP:将栈顶元素的引用计数增加1,并将它再次

Python源码剖析笔记3-Python执行原理初探

Python源码剖析笔记3-Python执行原理初探 本文简书地址:http://www.jianshu.com/p/03af86845c95 之前写了几篇源码剖析笔记,然而慢慢觉得没有从一个宏观的角度理解python执行原理的话,从底向上分析未免太容易让人疑惑,不如先从宏观上对python执行原理有了一个基本了解,再慢慢探究细节,这样也许会好很多.这也是最近这么久没有更新了笔记了,一直在看源码剖析书籍和源码,希望能够从一个宏观层面理清python执行原理.人说读书从薄读厚,再从厚读薄方是理解了

Python源码剖析笔记0 ——C语言基础

python源码剖析笔记0--C语言基础回顾 要分析python源码,C语言的基础不能少,特别是指针和结构体等知识.这篇文章先回顾C语言基础,方便后续代码的阅读. 1 关于ELF文件 linux中的C编译得到的目标文件和可执行文件都是ELF格式的,可执行文件中以segment来划分,目标文件中,我们是以section划分.一个segment包含一个或多个section,通过readelf命令可以看到完整的section和segment信息.看一个栗子: char pear[40]; static