AdapterView与Adapter(五) --AsyncQueryHandler

来源:互联网 发布:java 6 jre 32位下载 编辑:程序博客网 时间:2024/05/28 15:07

第一弹

今天晚上研究了一下啊AsyncQueryHandler,收获挺大,记录下重要知识点,以后继续补充研究。

研究AsyncQueryHandler这个类的时候遇到了几个重要的不清楚的知识点

1. Handler与Thread,Looper的关系

2. HandlerThread是干什么用的

3. ThreadLocal类是干什么用的

Handler主要是用来发送和处理消息,但是发送了消息后,消息是怎么传递的呢?这就是Looper的作用了,每个Handler中都会有一个Looper对象,如果在创建Handler的时候不指定,系统就会默认将当前线程的Looper绑定到Handler上,Looper对象中维护者一个消息队列,Hander发送的消息都会存储到这个消息队列中,Looper不断的遍历这个消息队列,取出消息,交给handleMessage方法处理。Looper属于哪个线程,hadleMessage方法就会在那个线程中执行。

HandlerThread不但能提供异步处理,Handler处理消息的方法也会在这个线程中执行,他最要的作用就是提供了一个线程。(这个类还有待研究)

ThreadLocal类主要是用来多个模块共享变量用的,但是不同线程之间的变量的值却不相同。

说明1:对象a,对象b比如说是某个类的实例对象,在模块A,B,C中共享对象a,还有对象b,在线程A中,模块A中设置a的值,在模块B,C中取出a的值,三个模块操作的是同一个值,但是对象a和对象b分别属于两个线程,他们是不同的。

AsyncQueryHandler的工作机制是什么?

AsyncQueryHandler继承了Handler对象,但是他提供的构造方法中却没有Looper参数,也就是说他和他所在的当前线程绑定,AsyncQueryHandler内部有一个Hhandler对象,叫mWorkerHandler,他和一个HandlerThread绑定,mWorkerHandler负责将打包好的消息发送,并且处理,并将结果作为消息发送给AsyncQueryHandler。他是怎么发送的?AsyncQueryHandler内部有一个WorkerArgs完美类,他封装了startAsyncQuery等方法的参数,并且通过这行代码

WorkerArgs args = new WorkerArgs();
       args.handler = this;

将当前Handler封装进去,发送到HandlerThread中去,mWorkerHandler处理完消息得到结果后,args.handler将结构发送给自己进行处理。(这就是线程间的通信了)

mWorkerHandler和一个子线程绑定,能够处理比较耗时的操作,AsyncQueryHandler提供异步处理。

 

总结:

Handler有两个作用,Handler用在一个线程中,就是实现异步操作。用在不同的线程之间,那就是异步操作加线程间通信。

补充:

HandlerThread:

先看他的类描述:Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.

这是一个包含了Looper对象的线程,这个looper可以用来创建Handler对象,记住:start()方法必须被调用,否则通过getLooper方法得到的looper对象是空的。通过调用start方法,就会去执行该线程的run方法, public void run() {

        mTid = Process.myTid();

        Looper.prepare();//创建一个Looper实例,并且存储在ThreadLocal中,ThreadLocal中维护一个HashMap,键是线程号

        synchronized (this) {

            mLooper = Looper.myLooper();//得到当前线程的Looper,就是刚才perpare方法中创建并存储的那个Looper实例

            Process.setThreadPriority(mPriority);

            notifyAll();

        }

        onLooperPrepared();

        Looper.loop();//开始轮询

        mTid = -1;

    }

 

 public static final void prepare() {

        if (sThreadLocal.get() != null) {

            throw new RuntimeException("Only one Looper may be created per thread");

        }

        sThreadLocal.set(new Looper());

    }

 

 public static final Looper myLooper() {

        return (Looper)sThreadLocal.get();

    }

 

 

AsyncQueryHandler是如何提供onxxxComplete方法给用户,由用户自己实现的?

public abstract class AsyncQueryHandler extends Handler  他是一个抽象类

 

MessageQueue是不是一个任务队列?

是,他是一个优先级队列(可以通过ArrayList的排序来实现)。它内部自己维护一个ArrayLsit集合,用来存储Message消息,Message消息有三种,普通消息,按照先发送先执行的FIFO原则进行;高优先级的消息,这种消息会直接插在队列的最前面,立刻执行;还有一种定时消息,类似于定时任务,到时间才执行。

Looper是如何轮询MessageQueue的?

当在主线程中使用Handler的时候,不用指定Looper,因为在主线程开启的时候,就已经调用了Looper.loop()方法开始轮询了。

挡在子线程中使用Handler的时候,通过调用Looper的prepare方法创建存储Looper对象,还得调用Looper.loop()方法开启轮询。

当配合HandlerThread使用Handler的时候,HandlerThread的run方法中调用了Looper.loop()方法。

 

    public static final void loop() {

        Looper me = myLooper();

        MessageQueue queue = me.mQueue;

        while (true) {

            Message msg = queue.next(); // might block

            //if (!me.mRun) {

            //    break;

            //}

            if (msg != null) {

                if (msg.target == null) {

                    // No target is a magic identifier for the quit message.

                    return;

                }

                msg.target.dispatchMessage(msg);

                msg.recycle();

            }

        }

    }

Message消息实现了Parcelable接口


第二弹

官方文档对AsyncQueryHandler的解释非常简洁

A helper class to help make handling asynchronousContentResolver queries easier

下面解释一番,其实明白之后就会发现,真的就是一句话的事情而已.

AsyncQueryHandler:异步的查询操作帮助类,其实它同样可以处理增删改,

查询其API便可知,它担供:

startInsert()

startDelete()

startUpdate()

startQuery()

这四个操作,并提供相对应的onXXXComplete方法,以供操作完数据库后进行其它的操作,这四个onXXXComplete方法都是空实现,以便我们只需要去实现我们关注的操作。

如题所说,让ContentResolver的查询操作更简单,

首先,若我们不用AsyncQueryHandler,那么,在UI 线程调用ContentResolve去操作数据库,比如查询,若你的数据库的数据很少还好,若很多,就会出现ANR了。一般解决ANR,就是开thread去解决。然后呢,既然开了新的Thread,就得通过Handler来和UI线程交互,也就是查询完之后通过Handler发一个message通知主线程去更新UI.这一系列的操作其实还是挺繁琐的.

所以,A helper class to help make handling asynchronousContentResolver queries easier

那么,若我们用AsyncQueryHandler怎样做呢,AsyncQueryHandler它就会主动地帮你开了Thread来避免ANR,并且它是继承于Handler,所以就可以通过onCompleteQuery来通知UI线程已经查询(删除,更新,增加)完成。 

所以,这两种实现方式的区别在于,工作是你自己写代码来做,还是调用现成的.

 


使用时直接调用startXXX方法即可。传入的通用参数如下:

token,一个令牌,主要用来标识查询,保证唯一即可.需要跟onXXXComplete方法传入的一致。(当然你也可以不一致,同样在数据库的操作结束后会调用对应的onXXXComplete方法 )

cookie,你想传给onXXXComplete方法使用的一个对象。(没有的话传递null即可)

Uri uri(进行查询的通用资源标志符):

projection 查询的列 

selection  限制条件 

selectionArgs 查询参数

orderBy 排序条件

 

private void startQuery() {            Uri uri = Sms.CONVESATION_URI;            mQueryHandler.startQuery(0, null, uri, CONVERSATION_PROJECTION, null, null, "sms.date desc");        }        // 写一个异步查询类        private final class QueryHandler extends AsyncQueryHandler {            public QueryHandler(ContentResolver cr) {                super(cr);            }                 @Override            protected void onQueryComplete(int token, Object cookie, Cursor cursor) {                super.onQueryComplete(token, cookie, cursor);                // 更新mAdapter的Cursor                mAdapter.changeCursor(cursor);            }        }  


第三弹

AsyncQueryHandler封装了调用者线程与工作线程的交互过程。交互的主体是两个Handler,一个运行在调用者线程中,一个运行在工作者线程中。通过提供onXXXComplete的回调接口,实现事件的完成处理。

 

public abstract class AsyncQueryHandler extends Handler {

    protected class WorkerHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {

              // 运行在工作者线程中

              WorkerArgs args = (WorkerArgs) msg.obj;

              // 向调用者传回信息

              Message reply = args.handler.obtainMessage(token);

        }

    }

    public AsyncQueryHandler(ContentResolver cr) {
        synchronized (AsyncQueryHandler.class) {

            // 启动工作者线程
            if (sLooper == null) {
                HandlerThread thread = new HandlerThread("AsyncQueryWorker");
                thread.start();
                sLooper = thread.getLooper();
            }
        }

        // 与工作者线程绑定的Hanlder
        mWorkerThreadHandler = createHandler(sLooper);
    }

    public void startQuery(...) {
        Message msg = mWorkerThreadHandler.obtainMessage(token);
        WorkerArgs args = new WorkerArgs();

        // 保存调用者Handler对象,以便回调
        args.handler = this;
        msg.obj = args;
        // 向工作者线程发出处理请求
        mWorkerThreadHandler.sendMessage(msg);
    }

    // 被子类重写的事件完成回调接口

    protected void onDeleteComplete(int token, Object cookie, int result) {
    }

    @Override
    public void handleMessage(Message msg) {
        // 运行在调用者线程

        switch (event) {
            case EVENT_ARG_QUERY:
                onQueryComplete(token, args.cookie, (Cursor) args.result);
                break;
        }   

   }

}

流程:startQuery->WorkerHandler::handleMessage->AsyncQueryHandler::handleMessage->onDeleteComplete



0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 特别压抑的时候怎么办 孕妇吃腊肉了怎么办 怀孕吃了午餐肉怎么办 剩米饭太硬怎么办? 月经推迟量少怎么办 怎么办早餐吃了1000 乐扣盒子打不开怎么办 不锈钢饭盒盖子打不开怎么办 电压力锅打不开盖子怎么办 保温饭盒打不开了怎么办 玻璃饭盒加热后打不开怎么办 玻璃饭盒盖子盖不紧怎么办 狗狗耳朵臭怎么办 白色洗手池发黄怎么办 热水壶木塞有味怎么办 过滤水壶效果不好怎么办 喝咖啡睡不着觉怎么办 食品流通许可证过期怎么办 水产养殖水体发白怎么办 生存战争找不到食物怎么办 执法记录仪肩扣怎么办 极米h1s死机了怎么办 受到伪基站骚扰怎么办 车载蓝牙没声音怎么办 工程现场更改方案怎么办 qq没有语音输入怎么办 执法记录仪丢了怎么办 vivox20无ip分配怎么办 x20无ip分配怎么办 手机ipv4不可用怎么办 ip地址不可用怎么办 lp地址配置错误怎么办 手机ip配置失败怎么办 wifi无ip分配怎么办 win10上传速度慢怎么办 三星s6图标变大怎么办 华为p9plus信号不好怎么办 手机wifi信号差怎么办? 华为wf信号不好怎么办 魅族打电话黑屏怎么办 魅族手机开不机怎么办