HandlerThread与AsyncQueryHandler源码分析
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:接收主线程发送的增删查改消息,并执行,将结果消息发送至主线程。