`
tansitongba
  • 浏览: 503375 次
文章分类
社区版块
存档分类
最新评论

AsyncQueryHandler的详细介绍

 
阅读更多
自从framework广泛应用后,我们不用面对赤裸裸的手机操作系统API,做一些重复而繁杂没有意义的事情。但天下没有免费的午餐,我们还是需
要学会高效正确的使用不同的framework,很多处理某一特定问题的手法在不同的framework中,用起来都会有所不同的。今天我们主要学习
andorid framework的使用。
  在Android中,下层是Linux的核,但上层的java做的framework把这一切封装的密不透风。以消息处理为例,在MFC中,我
们可以用PreTranslateMessage等东东自由处理消息,在C#中,Anders
Hejlsberg老大说了,他为我们通向底层开了一扇“救生窗”,但很遗憾,在Android中,这扇窗户也被关闭了(至少我现在没发现...)。
  在Android中,你想处理一些消息(比如:Keydown之类的...),你必须寻找Activity为你提供的一些重载函数(比如
onKeyDown之类的...)或者是各式各样的listener(比如OnKeyDownListner之类的...)。这样做的好处是显而易见的,
越多的自由就会有越多的危险和越多的晦涩,条条框框画好了,用起来省心看起来省脑,这是一个设计良好的framework应该提供的享受。对于我目前的工
程而言,我没有什么BT的需求在当前API下做不到的,google的设计ms还是很nice的。
  但世界是残酷的,有的时候我们还是必须有机制提供消息的分发和处理的,因为有的工作是不能通过直接调用来同步处理的,同时也不能通过
Activity中内嵌的消息分发和接口设定来做到,比如说事件的定时触法,异步的循环事件的处理,高耗时的工作等等。在Android中,它提供了一些
蛮有意思的方式来做这件事情(不好意思,我见不多识不广,我没见过类似玩法,有见过的提个醒 &&
嘴下超生^_^),它有一个android.os.Handler的类,这个类接受一个Looper参数,顾名思义,这是一个封装过的,表征消息循环的
类。默认情况下,Handler接受的是当前线程下的消息循环实例,也就是说一个消息循环可以被当前线程中的多个对象来分发,来处理(在UI线程中,系统
已经有一个Activity来处理了,你可以再起若干个Handler来处理...)。在实例化一个
handlerInstance之后,你可以通过sendMessage等消息发送机制来发送消息,通过重载handleMessage等函数来分发消
息。但是!该handlerInstance能够接受到的消息,只有通过handlerInstance.obtainMessage构造出来的消息(这
种说法是不确切的,你也可以手动new一个Message,然后配置成该handlerInstance可以处理的,我没有跟进去分析其识别机制,有兴趣
的自己玩吧^_^)。也就是说A, B, C,
D都可以来处理同一线程内的消息分发,但各自都只能处理属于自己的那一份消息,这抹杀了B想偷偷进入A领地,越俎代庖做一些非份之事的可能(从理论上
看,B还是有可能把消息伪装的和A他们家的一样,我没有尝试挑战一下google的智商,有BT需求的自行研究^_^)。这样做,不但兼顾了灵活性,也确
保了安全性,用起来也会简单,我的地盘我做主,不用当心伤及无辜,左拥右抱是一件很开心的事情。。。
  很显然,消息发送者不局限于自己线程,否者只能做一些定时,延时之类的事情,岂不十分无趣。在实例化Handler的时候,Looper可以是
任意线程的,只要有Handler的指针,任何线程也都可以sendMessage(这种构造方式也很有意思,你可以在A线程里面传B线程的Looper
来构造
Handler,也可以在B线程里构造,这给内存管理的方法带来很大的变数...)。但有条规则肯定是不能破坏的,就是非UI线程,是不能触碰UI类的。
在不同平台上有很多解决方式(如果你有多的不能再多的兴趣,可以看一下很久很久以前我写的一个,不SB不要钱)。我特意好好跟了一下android中的
AsyncQueryHandler类,来了解google官方的解决方案。
  AsyncQueryHandler是Handler的子类,文档上说,如果处理ContentProvider相关的内容,不用需要自行定义
一套东西,而可以简单的使用async方式。我想指代的就应该是AsyncQueryHandler类。该类是一个典型的模板类,为
ContentProvider
的增删改查提供了很好的接口,提供了一个解决架构,final了一些方法,置空了一些方法。通过派生,实例化一些方法(不是每个对
ContentProvider的处理多需要全部做增删改查,我想这也是该类默认置空一些方法而不是抽象一些方法的原因),来达到这个目的。在内部,该类
隐藏了多线程处理的细节,当你使用时,你会感觉异常便利。以query为例,你可以这么来用:
// 定义一个handler,采用的是匿名类的方式,只处理query,因此只重写了onQueryComplete函数:
queryHandler = new AsyncQueryHandler(this.getContentResolver()){ // 传入的是一个ContentResolver实例,所以必须在OnCreate后实例化该Handler类
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
// 在这里你可以获得一个cursor和你传入的附加的token和cookie。
// 该方法在当前线程下(如果传入的是默认的Looper话),可以自由设定UI信息
}
};
 调用时只需要调用startQuery(int token, Object cookie, ContentURI uri,
String[] projection, String selection, String[] selectionArgs, String
sortOrder)函数即可:
queryHandler.startQuery(token, cookie, uri, projection, selection, selectionArgs, sortBy);
  可见,该类的使用是多么简单(其实现可不会很容易,因为我尝试做了一次造车轮的工作*_*),比直接用Handler简单无数倍。但让我倍感孤
独的是,不知道是没人做异步的ContentProvider访问,还是这个类使用太过于弱智(这个使用方法可是我摸索了半天的啊,难道我真的如此的弱
@_@),抑或是大家都各有高招,从SDK到网上,没有任何关于该类的有点用的说明。而我又恰巧悲伤的发现,这个类其实有很多的问题,比如他吃掉异常,有
错误时只是简单的返回null指针(这个其实不能怪他,你可以看看这里...);当你传一个null的ContentResolver进去的时候,没有任
何异常,只是莫名其妙的丢弃所有消息,使你陷入苦苦的等待而不知其因;更愤慨的是,他的token传递竟然有Bug(难道还是我使用不
对&_&),从startXX传入的token,到了onXXComplete里面一律变成1,而文档上明明写着两个是一个东西(我的解
决方法是用cookie做token,这个不会丢*_*)。不过我暂时还没有遗弃它的打算,虽然没人理睬,虽然有一堆问题,虽然我按图索骥造了个新轮子,
但为了节省剩下的一些无聊的工作,我决定苟且偷生了。。。
  还是习惯性跑题了,其实,我是想通过我对这个类的无数次Debugger跟进,说说它的多线程异步处理的解决策略的。他的基本策略如下:
  1. 当你实例化一个AsyncQueryHandler类时(包括其子类...),它会单件构造一个线程(后面会详述...),这个线程里面会构建一个消息循环。
  2. 获得该消息循环的指针,用它做参数实例化另一个Handler类,该类为内部类。至此,就有了两个线程,各自有一个Handler来处理消息。
  3. 当调用onXXX的时候,在XXX函数内部会将请求封装成一个内部的参数类,将其作为消息的参数,将此消息发送至另一个线程。
  4. 在该线程的Handler中,接受该消息,并分析传入的参数,用初始化时传入的ContentResolver进行XXX操作,并返回Cursor或其他返回值。
  5. 构造一个消息,将上述返回值以及其他相关内容绑定在该消息上,发送回主线程。
  6. 主线程默认的AsyncQueryHandler类的handleMessage方法(可自定义,但由于都是内部类,基本没有意义...)会分析该消息,并转发给对应的onXXXComplete方法。
  7. 用户重写的onXXXComplete方法开始工作。
  这就是它偷偷摸摸做过的事情,基本还是很好理解的。我唯一好奇的是它的线程管理方式,我猜测他是用的单件模式。第一个
AsyncQueryHandler的实例化会导致创建一个线程,从此该线程成为不死老处男,所有的ContentResolver相关的工作,都由该线
程统一完成。个人觉得这种解决方式很赞。本来这个线程的生命周期就很难估量,并且,当你有一个ContentProvider的请求的时候,判断你会做更
多的类似操作并不过分。就算错了,花费的也只是一个不死的线程(与进程同生死共存亡...),换来的却是简单的生命周期管理和无数次线程生死开销的节约。
同时另外一个很重要的问题,他并会涉及到单件中数据同步的问题,每个类都有各自的Handler类,彼此互不干扰,分发可以分别进行。当多个数据请求的时
候,在同一个ContentResolver上进行的可能微乎其微,这就避免了堵塞。总而言之,这套解决办法和Android的整体设计算是天作之合了。
  建议,如果你有什么非ContentProvider操作,却需要异步多线程执行的话,模拟一套,是个不错的策略,当然,具体情况具体分析,生搬硬套是学不好马列主义的。。。android的消息机制,异步和多线程其实并不复杂,只要有心,就能够学会。
分享到:
评论

相关推荐

    使用AsyncQueryHandler操作ContentProvider

    下面将详细介绍如何使用AsyncQueryHandler来操作ContentProvider以及它的内部工作原理。 **1. 创建AsyncQueryHandler实例** 首先,在需要使用AsyncQueryHandler的类中创建一个实例,通常是在Activity或Fragment中...

    Android 小积累之AsyncQueryHandler用法

    `AsyncQueryHandler`是Android系统提供的一种用于在后台线程执行SQLite数据库查询的工具类,它可以避免因为长时间数据库操作导致的ANR(Application Not Responding)错误。下面我们将深入探讨`AsyncQueryHandler`的...

    AsyncQueryHandler 手机联系人信息读取

    例如,你可以创建一个Contact类来存储每个联系人的详细信息,并将结果添加到一个Contact对象列表中。 为了展示如何使用`AsyncQueryHandler`,让我们看一个简单的例子: ```java public class ...

    contentprovider异步查询帮助类:AsyncQueryHandler

    这篇博客()可能会详细解析这个帮助类的工作原理和使用方法。 `AsyncQueryHandler`是基于`Handler`和`HandlerThread`实现的异步处理模型。在Android中,`Handler`用于发送和处理消息,`HandlerThread`则是一个拥有...

    QuickContactBadge和AsyncQueryHandler实现联系人列表

    本代码是QuickContactBadge和AsyncQueryHandler实现联系人列表的完美实现,对初级程序员会有很大的帮助,可以直接拿来用,还带了首字母拼音的滑动栏,里面有自定义控件可以让你好好学习

    AsyncQueryHandler及ContentProvider代码实例

    本篇文章将详细解析这两个组件以及相关的Adapter用法。 首先,我们来看 `ContentProvider`。`ContentProvider` 是Android系统提供的一种数据管理机制,它可以封装数据存储(如SQLite数据库)并提供统一的接口供其他...

    Android使用AsyncQueryHandler实现获取手机联系人功能

    本文将详细介绍如何使用`AsyncQueryHandler`实现获取手机联系人的功能。 首先,我们来看一下布局文件`main.xml`。这是一个简单的线性布局,包含一个按钮`bt_getContacts`,用户点击这个按钮时,程序将启动获取联系...

    android AlphabetListView

    `AsyncQueryHandler`介绍 `AsyncQueryHandler`是Android中的一个异步查询处理类,主要用于数据库操作。它基于`Handler`机制,可以避免在主线程进行耗时操作,防止应用因ANR(Application Not Responding)问题而...

    安卓数据库操作案例

    以下是这些关键知识点的详细说明。 1. **SQLite数据库**: 安卓系统默认支持SQLite数据库,这是一个轻量级的关系型数据库,适用于移动设备存储结构化数据。SQLite数据库以文件形式存在,支持SQL语法,便于进行数据...

    日历事件多条删除

    接下来,我们将详细讨论这些知识点。 首先,`ActionBar`是Android UI设计模式中的一种,它位于应用顶部,提供应用程序的品牌标识、导航、操作以及搜索等功能。在实现"日历事件多条删除"时,`ActionBar`可能用于展示...

    Android Contacts查询全过程

    本文档详细介绍了一个典型的联系人查询流程,包括初始化设置、模式选择、查询启动及数据处理等关键步骤。 ### 初始化设置与模式设定 #### onCreate() 方法详解 初始化阶段是联系人查询过程的第一步。`onCreate()`...

    android学习笔记之消息机制,异步和多线程.pdf

    本文将深入探讨这两个主题,并结合Android框架进行详细解释。 首先,Android的消息机制主要由`Handler`、`Looper`和`Message`三者构成。`Handler`是一个用于发送和处理消息的对象,它接收`Message`对象并调用`...

    TestContentProvider01

    这个例子,主要是在db数据库中新建一个表,并提供正常的增,删,改,查操作和使用AsyncQueryHandler来异步对db数据库的数据进行增,删,改,查操作,以减少操作的时间,提高效率.csdn详细说明网址:...

    android 识别U盘以及读写文件的方法

    以下将详细讲解这些过程。 1. **识别U盘** Android系统通过ContentProvider来管理和暴露存储设备,包括U盘。识别U盘主要依赖于`ContentResolver`和`AsyncQueryHandler`这两个组件。 - `ContentResolver` 是...

    基于Android的短信高效管理的研究.pdf

    作者提出利用AsyncQueryHandler异步查询辅助类来获取短信会话列表,避免因长时间阻塞主线程导致的ANR(Application Not Responding)异常。这种异步处理方式可以提高系统的响应速度和用户体验。 在短信显示方面,...

    android学习笔记之消息机制,异步和多线程[参考].pdf

    例如,`AsyncQueryHandler`是Android提供的一种处理与`ContentProvider`交互的异步方式,它是`Handler`的子类,简化了对数据库查询的处理。通过继承`AsyncQueryHandler`并重写相关方法,开发者可以轻松实现数据库...

    Android开发问题集锦第三期

    ### Android开发问题集锦第三期知识点详解 #### 一、Android线程同步之...以上是关于Android开发问题集锦第三期的一些关键知识点的详细介绍。希望这些内容能够帮助开发者更好地理解和掌握Android开发中的相关技术。

    Android-QuickSearchBox程序源码.zip

    这一功能通过`AsyncQueryHandler`实现,它是异步处理数据库查询的工具类。在`SuggestionsProvider`中,`onStartQuery()`和`onStartUpdate()`方法处理查询和更新请求,`onQueryComplete()`则在后台线程完成查询后回调...

    android Contacts增删改查.docx

    - `mQueryHandler`是`QueryHandler`的实例,它继承自`AsyncQueryHandler`,负责异步查询联系人数据。 - 在`onResume`方法中,会检查是否需要执行查询。如果是在默认模式下,并且是第一次打开应用,会调用`...

Global site tag (gtag.js) - Google Analytics