博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HandlerThread与AsyncQueryHandler源码分析
阅读量:7125 次
发布时间:2019-06-28

本文共 10992 字,大约阅读时间需要 36 分钟。

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中的LooperHandler 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
(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://mveel.baihongyu.com/

你可能感兴趣的文章
无法打开物理文件mdf,操作系统错误 5:"5(拒绝訪问。)"
查看>>
Dynamic CRM 2013学习笔记(二十三)CRM JS智能提示(CRM 相关的方法、属性以及页面字段),及发布前调试...
查看>>
ecside使用笔记(1)
查看>>
eclipse+webservice开发实例
查看>>
js undefined易错分析
查看>>
程序员必须知道的几个Git代码托管平台(转)
查看>>
PHP 二维数组根据相同的值进行合并
查看>>
微信JS-SDK使用权限签名算法的服务端实现(.net版本)
查看>>
windows下ruby安装环境配置
查看>>
Wndows 主进程(Rundll32)已停止工作
查看>>
C#的百度地图开发(一)发起HTTP请求
查看>>
用12306购票所想到的(改善的地方)
查看>>
Java设计模式(1)工厂模式(Factory模式)
查看>>
硬盘惊魂记
查看>>
mysql函数
查看>>
php xls 导出乱码解决方案
查看>>
[Android Traffic] 让android应用在传输网络数据的时候更省电
查看>>
Eclipse中Maven插件配置
查看>>
对于GetBuffer() 与 ReleaseBuffer() 的一些分析
查看>>
FluentData,一个轻量级开源的.NET ORM数据持久化框架
查看>>