AsyncQueryHandler代码分析

来源:互联网 发布:linux 破解root密码 编辑:程序博客网 时间:2024/06/05 17:23

  • AsyncQueryHandler代码分析
    • 一概述
    • 二AsyncQueryHandler
      • 2-1 源代码
      • 2-2 构造方法
      • 2-3 增删改查
      • 2-4 操作流程
    • 三知识点总结
      • 3-1 多线程同步
      • 3-2 异步回调机制
      • 3-3 思考

AsyncQueryHandler代码分析

一、概述

异步的查询操作帮助类,可以处理增删改查(ContentProvider提供的数据)。查询数据库,如果数据太多会造成主线程堵塞导致ANR,所以需要开启子线程,然后 用Handler将结果回传。而使用android系统提供的AsyncQueryHandler方便的实现这个过程。

二、AsyncQueryHandler

#2-1 源代码

public abstract class AsyncQueryHandler extends Handler {    private static final String TAG = "AsyncQuery";    private static final boolean localLOGV = false;    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;    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;    }    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;            }            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();        }    }    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);    }    public void startQuery(int token, Object cookie, Uri uri,            String[] projection, String selection, String[] selectionArgs,            String orderBy) {        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);    }    public final void cancelOperation(int token) {        mWorkerThreadHandler.removeMessages(token);    }    public final void startInsert(int token, Object cookie, Uri uri,            ContentValues initialValues) {        Message msg = mWorkerThreadHandler.obtainMessage(token);        msg.arg1 = EVENT_ARG_INSERT;        WorkerArgs args = new WorkerArgs();        args.handler = this;        args.uri = uri;        args.cookie = cookie;        args.values = initialValues;        msg.obj = args;        mWorkerThreadHandler.sendMessage(msg);    }    public final void startUpdate(int token, Object cookie, Uri uri,            ContentValues values, String selection, String[] selectionArgs) {        Message msg = mWorkerThreadHandler.obtainMessage(token);        msg.arg1 = EVENT_ARG_UPDATE;        WorkerArgs args = new WorkerArgs();        args.handler = this;        args.uri = uri;        args.cookie = cookie;        args.values = values;        args.selection = selection;        args.selectionArgs = selectionArgs;        msg.obj = args;        mWorkerThreadHandler.sendMessage(msg);    }    public final void startDelete(int token, Object cookie, Uri uri,            String selection, String[] selectionArgs) {        Message msg = mWorkerThreadHandler.obtainMessage(token);        msg.arg1 = EVENT_ARG_DELETE;        WorkerArgs args = new WorkerArgs();        args.handler = this;        args.uri = uri;        args.cookie = cookie;        args.selection = selection;        args.selectionArgs = selectionArgs;        msg.obj = args;        mWorkerThreadHandler.sendMessage(msg);    }    protected void onQueryComplete(int token, Object cookie, Cursor cursor) {        // Empty    }    protected void onInsertComplete(int token, Object cookie, Uri uri) {        // Empty    }    protected void onUpdateComplete(int token, Object cookie, int result) {        // Empty    }    protected void onDeleteComplete(int token, Object cookie, int result) {        // Empty    }    @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;        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;        }    }}

#2-2 构造方法

构造方法里初始化子线程Looper,使用AsyncQueryHandler处理的任务都运行在该子线程中。AsyncQueryHandler本身也可以在多线程里使用,所以构造方法里使用了synchronized 避免创建时出现多线程问题。值得注意的是多线程编程时,一定要多考虑静态成员变量在多线程下的不同步问题。

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

#2-3 增、删、改、查

增、删、改、查操作通过WorkerArgs和WorkerThreadHandler运行在子线程里,并且在WorkerArgs里传入当前AsyncQueryHandler 引用用于子线程操作完成后回调到传入的AsyncQueryHandler 里。

    #AsyncQueryHandler    public void startQuery(int token, Object cookie, Uri uri,            String[] projection, String selection, String[] selectionArgs,            String orderBy) {        Message msg = mWorkerThreadHandler.obtainMessage(token);        msg.arg1 = EVENT_ARG_QUERY;        ......        mWorkerThreadHandler.sendMessage(msg);    }-----------------------------------------------        #WorkerThreadHandler        @Override        public void handleMessage(Message msg) {            ......            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;                    }           ......        }     }

#2-4 操作流程

查询时把token和EVENT_ARG_QUERY重要参数传入到子线程handleMessage里,子线程handleMessage处理完实际的查询操作再把token和EVENT_ARG_QUERY回传到AsyncQueryHandler
里,并且通过token和EVENT_ARG_QUERY来识别是哪一次查询。

    #AsyncQueryHandler    public void startQuery(int token, Object cookie, Uri uri,            String[] projection, String selection, String[] selectionArgs,            String orderBy) {        Message msg = mWorkerThreadHandler.obtainMessage(token);        msg.arg1 = EVENT_ARG_QUERY;        ......        mWorkerThreadHandler.sendMessage(msg);    }--------------------------------------------            #WorkerThreadHandler            ......            WorkerArgs args = (WorkerArgs) msg.obj;            int token = msg.what;            int event = msg.arg1;            //实际查询操作            ......            //查询完后将token和event再传回到AsyncQueryHandler             Message reply = args.handler.obtainMessage(token);            reply.obj = args;            reply.arg1 = msg.arg1;            ......            reply.sendToTarget();        }------------------------------------------        #AsyncQueryHandler        ......        int token = msg.what;        int event = msg.arg1;        switch (event) {            case EVENT_ARG_QUERY:                onQueryComplete(token, args.cookie, (Cursor) args.result);                break;        ......        }

三、知识点总结

#3-1 多线程同步

使用一个Looper是保证通过AsyncQueryHandler处理的任务都运行在同一个子线程里;因为AsyncQueryHandler本身可以在多线程里执行,所以sLooper 需要做了一个同步的处理,避免多线程引起判断不正确的问题。

       synchronized (AsyncQueryHandler.class) {            if (sLooper == null) {                HandlerThread thread = new HandlerThread("AsyncQueryWorker");                thread.start();                sLooper = thread.getLooper();            }        }

#3-2 异步回调机制

AsyncQueryHandler整个代码结构非常清晰和简洁,整个操作流程采用了两个Handler相互通信实现。AsyncQueryHandler发送消息到WorkerThreadHandler,然后在WorkerThreadHandler处理完实际操作后再回发消息到AsyncQueryHandler完成一次通信流程。

#3-3 思考

顾名思义AsyncQueryHandler用于异步查询操作,且是单线程查询操作,不适合用于查询大量网络信息的APP;考虑到实际使用场景AsyncQueryHandler的使用范围也有一定的限制,但是我们可以参照AsyncQueryHandler写一个比如说AsyncHandler比较通用的异步处理帮助类。

原创粉丝点击