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比较通用的异步处理帮助类。
- AsyncQueryHandler代码分析
- AsyncQueryHandler分析
- android AsyncQueryHandler的分析
- AsyncQueryHandler 分析 缺陷
- android AsyncQueryHandler的分析
- android AsyncQueryHandler的分析
- AsyncQueryHandler源码分析
- AsyncQueryHandler类的简单分析
- AsyncQueryHandler
- AsyncQueryHandler
- AsyncQueryHandler
- AsyncQueryHandler
- AsyncQueryHandler
- AsyncQueryHandler
- AsyncQueryHandler
- AsyncQueryHandler
- AsyncQueryHandler
- AsyncQueryHandler
- 关于爬虫爬取图片被防盗链的解决
- Rust使用Cargo
- js判断是微信、QQ内置浏览器打开页面
- Rust 变量绑定
- Rust 函数
- AsyncQueryHandler代码分析
- IntentService解析及使用规范
- Update Strategy小记
- Rust 数据类型
- 使用ssh公钥实现免密码登录
- 支付网关接入中的ssl连接和签名调试tips
- Rust 运算符
- 51Nod-1305 Pairwise Sum and Divide
- 51Nod-1344 走格子