作用: 对DB数据库进行异步操作,加快其数据处理的速度. 例如几千联系人的数据读取,按正常的处理速度会非常的慢,
使用AsyncQueryHandler,这就会大大的加快速度,增加用户的良好体验。
为什么会有AsyncQueryHandler?
1,若不用AsyncQueryHandler,直接在UI 线程调用ContentResolve去操作数据库,比如查询.如果数据库的数据很少,
无需担心ANR问题;如果有大量的数据,就会出现ANR。一般解决方法就是构造thread去查询,然后通过Handler来和
UI线程交互,让UI线程知道何时查询完毕,并且可以更新UI将查询的结果表现出来。
2,如果用AsyncQueryHandler,AsyncQueryHandler它就会主动地构造Thread来避免ANR,并且它是继承于Handler,
所以就可以通过回调方法来通知UI线程已经操作完成。
所以AsyncQueryHandler会做以下2件事情,
1,构造thread,
2,在thread中操作完成数据库之后切换到主线程并通过回调方法来进行交互。
AsyncQueryHandler是一个抽象类,定义如下,
public abstract class AsyncQueryHandler extends Handler {
AsyncQueryHandler的构造方法如下,
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);
}
createHandler方法如下,
protected Handler createHandler(Looper looper) {
return new WorkerHandler(looper);
}
WorkerHandler是AsyncQueryHandler的一个内部类,继承于Handler,
protected class WorkerHandler extends Handler {
由此可知, AsyncQueryHandler 首先利用HandlerThread开启了一个线程,并且利用该线程的Looper构造WorkerHandler对象,
这样当AsyncQueryHandler (UI线程) 给mWorkerThreadHandler发送消息时,就可以切换到子线程中执行,执行完成之后
mWorkerThreadHandler就会给AsyncQueryHandler发送消息,切换到主线程中执行。
AsyncQueryHandler有5个public方法,分别对应数据库的增删改查(startInsert/startDelete/ startUpdate/startQuery)方法,
还有一个停止的方法(cancelOperation),增删改查4个方法的逻辑完全相同,以startQuery方法为例论述原理。
startQuery方法如下,
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();//构造WorkerArgs对象
args.handler = this;// AsyncQueryHandler对象
args.uri = uri;// 数据库的URI对象
args.projection = projection;
args.selection = selection;
args.selectionArgs = selectionArgs;
args.orderBy = orderBy;
args.cookie = cookie;
msg.obj = args;
mWorkerThreadHandler.sendMessage(msg);
}
主要是利用内部类WorkerArgs封装消息.4个方法对应不同的消息,
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;
WorkerHandler中的handleMessage主要处理逻辑如下,
1,从WorkerArgs中取出封装的消息,
final ContentResolver resolver = mResolver.get();//ContentResolver对象
if (resolver == null) return;
WorkerArgs args = (WorkerArgs) msg.obj;
int token = msg.what;
int event = msg.arg1;
2,根据不同的消息分别处理,调用数据库进行增删改查操作,对查询消息的处理如下,
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;
3,操作完成之后,给AsyncQueryHandler发送消息,
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的handleMessage方法主要是根据不同的消息分别调用不同的回调方法,
1,查询数据库完成之后调用onQueryComplete方法,
case EVENT_ARG_QUERY:
onQueryComplete(token, args.cookie, (Cursor) args.result);
break;
2,增加数据库完成之后调用onInsertComplete方法,
case EVENT_ARG_INSERT:
onInsertComplete(token, args.cookie, (Uri) args.result);
break;
3,更新数据库完成之后调用onUpdateComplete方法,
case EVENT_ARG_UPDATE:
onUpdateComplete(token, args.cookie, (Integer) args.result);
break;
4,删除数据库完成之后调用onDeleteComplete方法,
case EVENT_ARG_DELETE:
onDeleteComplete(token, args.cookie, (Integer) args.result);
break;
当然,这4个方法并不是抽象方法,而是protected方法.因此,子类并不需要实现所有4个方法,只需要根据需要实现即可。
AsyncQueryHandler主要就是利用内部类WorkerHandler和AsyncQueryHandler之间发送消息进行线程间的切换,
增删改查耗时操作都是在子线程中执行,并且执行完成之后利用回调进行交互。