HandlerThread与AsyncQueryHandler源码分析
1. HandlerThread
HandlerThread继承自Thread,其本质还是一个Thread子类,只不过它内部封装了一个Looper,可以进行消息轮询,实现主线程向子线程发送消息,子线程根据消息类型执行相应代码,主要是耗时操作,如访问IO、查询数据库,但不建议进行网络请求,因为子线程中的消息是串行执行,访问网络较为耗时,因此HandlerThread适合处理耗时较短的任务。
1.1 HandlerThread源码分析
HandlerThread的内容并不多
package android.os;
public class HandlerThread extends Thread {
int mPriority;//线程优先级
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
//初始化Looper后,在开启loop循环前进行一些准备工作
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();//给当前线程创建Looper
synchronized (this) {
mLooper = Looper.myLooper();//将当前线程的Looper传给mLooper变量
notifyAll();
}
Process.setThreadPriority(mPriority);//设置线程优先级
onLooperPrepared();
Looper.loop();//开启消息循环
mTid = -1;
}
HandlerThread类中包含一个Looper对象mLooper,这个Looper对象在run方法中初始化,loop()开启后,不断的循环从MessageQueue中取出消息处理,当没有消息的时候会阻塞,有消息的到来的时候会唤醒。
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
getLooper方法返回当前线程创建的Looper对象,若调用该方法时Looper还未创建,则一直等待直到Looper创建完毕。
当HandlerThread使用完后,需要让线程内的Looper退出循环
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
1.2 HandlerThread用法
HandlerThread handlerThread = new HandlerThread("subThread");
handlerThread.start();//开启子线程,同时也开启了子线程内消息循环
Looper looper = handlerThread.getLooper();//获取HandlerThread中的Looper
Handler handler = new Handler(looper){ //初始化Handler,与子线程Looper绑定
@Override
public void handleMessage(Message msg){
//在子线程中执行
}
};
2. AsyncQueryHandler
AsyncQueryHandler是一个异步查询操作帮助类,封装了HandlerThread和ContentResolver,可以方便地将耗时操作放在子线程中执行,并将执行结果回传至主线程中处理。
2.1 AsyncQueryHandler源码分析
AsyncQueryHandler继承了Handler,但是他提供的构造方法中却没有Looper参数,也就是说它与其所在的当前线程的looper绑定。
AsyncQueryHandler构造方法:
public AsyncQueryHandler(ContentResolver cr) {
super();//在父类构造方法中绑定了looper
mResolver = new WeakReference<ContentResolver>(cr);
synchronized (AsyncQueryHandler.class) {
if (sLooper == null) {
//创建HandlerThread,用于执行耗时的操作
HandlerThread thread = new HandlerThread("AsyncQueryWorker");
thread.start();
sLooper = thread.getLooper();
}
}
//创建工作线程的Handler对象
mWorkerThreadHandler = createHandler(sLooper);
}
protected Handler createHandler(Looper looper) {
return new WorkerHandler(looper);
}
AsyncQueryHandler的构造方法中传入ContentResolver参数,然后创建一个对应的弱引用对象mResolver。
同时,创建了一个HandlerThread线程并开启,初始化了mWorkerThreadHandler对象并与HandlerThread线程的looper进行绑定。mWorkerThreadHandler是一个WorkerHandler类的对象,下面看WorkerHandler类:
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;//可理解为消息的ID
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;
}
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;
}
// passing the original token value back to the caller
// on top of the event values in arg1.
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();
}
}
WorkerHandler类是AsyncQueryhandler的内部类,继承了Handler,它的构造函数中传入looper作为参数,与之绑定。由上可知,实例化的WorkerHandler对象是mWorkerThreadHandler,它与HandlerThread的looper绑定,因此其handleMessage方法会在子线程中执行,处理耗时的操作
在handleMessage方法中,首先获取到mResolver对象,然后从消息中获取到WorkerArgs对象、event和token。
event:消息类型,AsyncQueryhandler中定义了四种消息类型,分别对应增删查改的四种操作
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;
token: 我理解为消息的ID,比如查询操作可能有很多次,每次都是发送不同的消息,因此要标识其ID,这在AsyncQueryhandler暴露的增删查改方法中也需要作为参数传入。当要取消某个操作时,执行cancelOperation方法,传入的参数就是token
public final void cancelOperation(int token) {
mWorkerThreadHandler.removeMessages(token);
}
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;
}
然后判断消息类型,跟据消息类型,进行相应的操作,以查询为例:
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;
就是基本的查询操作,将查询的结果保存在args.result,最后:
Message reply = args.handler.obtainMessage(token);
reply.obj = args;
reply.arg1 = msg.arg1;
reply.sendToTarget();
注意:这里将带有操作结果的args对象封装入一个message中,这个message的handler是args中保存的handler,然后将这个消息发送出去。
那么,WorkerHandler类中handleMessage方法的消息从何处发来的?reply这个消息又将发向哪里?
handleMessage方法中的消息是主线程执行操作时发送的,这里以查询为例,在AsyncQueryHandler类中:
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;//指向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);
}
这里开启异步查询操作,首先获取一个消息,这个消息将携带查询操作所需的各种参数,这些参数被封装在WorkerArgs中,这个消息将被发送到工作线程(子线程)中的MessageQueue,等待被执行,因此,子线程HandlerThread将会接收到这个消息,所以该消息的handler对象为mWorkerThreadHandler。
注意,在构造args对象后,args.handler = this
将args对象的handler指向了AsyncQueryHandler对象,因此,在WorkerHandler的handleMessage方法中:
Message reply = args.handler.obtainMessage(token);
reply.obj = args;
reply.arg1 = msg.arg1;
reply.sendToTarget();
这个reply消息将会发送到AsyncQueryHandler对象的handleMessage方法中,也就是将查询结果发送到主线程中的handleMessage方法中。
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;
}
}
}
子线程的消息发送到该handleMessage方法中,然后根据消息中的操作结果执行相应的代码。这样整个异步查询流程就完成了。
2.2 AsyncQueryHandler用法
QueryHandler handler = new QueryHandler(getContentResolver());//创建异步查询对象
//开启查询,传入查询参数
handler.startQuery(token, cookie, uri, projection, selection, selectionArgs, String orderBy)
//自定义AsyncQueryHandler类
private final class QueryHandler extends AsyncQueryHandler{
public QueryHandler(ContentResolver cr) {
super(cr);
//do something
}
//查询完毕后将结果后回传至此方法
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
//do something
}
}
3. 总结
AsyncQueryHandler是一个Handler,其内部还有一个Handler类WorkerHandler
AsyncQueryHandler:与创建它的线程(调用线程)的looper绑定
AsyncQueryHandler.handleMessage:处理子线程发来的消息,消息携带操作结果
WorkerHandler:与HandlerThread线程(工作线程)的looper绑定
AsyncQueryHandler.handleMessage:接收主线程发送的增删查改消息,并执行,将结果消息发送至主线程。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。