1、有了 framework 后,我们不用面对赤裸裸的 OS API,做一些重复而繁杂的事情。但天下没有免费的午餐,我们还是需要学会高效正确的使用不同的 framework,很多处理某一特定问题的手法在不同的 framework 中,用起来都会有所不同的。在 Android 中,下层是 Linux 的核,但上层的 java 做的 framework 把这一切封装的密不透风。以消息处理为例,在 MFC 中,我们可以用 PreTranslateMessage 等东东自由处理消息,在 C#中,Anders Hejlsberg 老大说了,他为我们通向底层开了一扇“救生窗” ,但很遗憾,在 Android
2、中,这扇窗户也被关闭了(至少我现在没发现.) 。在 Android 中,你想处理一些消息(比如:Keydown 之类的.) ,你必须寻找 Activity 为你提供的一些重载函数(比如 onKeyDown 之类的.)或者是各式各样的 listener(比如OnKeyDownListner 之类的.) 。这样做的好处是显而易见的,越多的自由就会有越多的危险和越多的晦涩,条条框框画好了,用起来省心看起来省脑,这是一个设计良好的framework 应该提供的享受。对于我目前的工程而言,我没有什么 BT 的需求在当前 API 下做不到的,google 的设计 ms 还是很 nice 的。但世界是残酷的
3、,有的时候我们还是必须有机制提供消息的分发和处理的,因为有的工作是不能通过直接调用来同步处理的,同时也不能通过 Activity 中内嵌的消息分发和接口设定来做到,比如说事件的定时触法,异步的循环事件的处理,高耗时的工作等等。在 Android中,它提供了一些蛮有意思的方式来做这件事情(不好意思,我见不多识不广,我没见过类似玩法,有见过的提个醒 / 调用时只需要调用 startQuery(int token, Object cookie, ContentURI uri, String projection, String selection, String selectionArgs, Str
4、ing sortOrder)函数即可:queryHandler.startQuery(token, cookie, uri, projection, selection, selectionArgs, sortBy);可见,该类的使用是多么简单(其实现可不会很容易,因为我尝试做了一次造车轮的工作*_*) ,比直接用 Handler 简单无数倍。但让我倍感孤独的是,不知道是没人做异步的ContentProvider 访问,还是这个类使用太过于弱智(这个使用方法可是我摸索了半天的啊,难道我真的如此的弱_) ,抑或是大家都各有高招,从 SDK 到网上,没有任何关于该类的有点用的说明。而我又恰巧悲伤的
5、发现,这个类其实有很多的问题,比如他吃掉异常,有错误时只是简单的返回 null 指针(这个其实不能怪他,你可以看看这里.) ;当你传一个 null的 ContentResolver 进去的时候,没有任何异常,只是莫名其妙的丢弃所有消息,使你陷入苦苦的等待而不知其因;更愤慨的是,他的 token 传递竟然有 Bug(难道还是我使用不对&_&) ,从 startXX 传入的 token,到了 onXXComplete 里面一律变成 1,而文档上明明写着两个是一个东西(我的解决方法是用 cookie 做 token,这个不会丢*_*) 。不过我暂时还没有遗弃它的打算,虽然没人理睬,虽然有一堆问题,虽
6、然我按图索骥造了个新轮子,但为了节省剩下的一些无聊的工作,我决定苟且偷生了。 。 。还是习惯性跑题了,其实,我是想通过我对这个类的无数次 Debugger 跟进,说说它的多线程异步处理的解决策略的。他的基本策略如下:1. 当你实例化一个 AsyncQueryHandler 类时(包括其子类.) ,它会单件构造一个线程(后面会详述.) ,这个线程里面会构建一个消息循环。2. 获得该消息循环的指针,用它做参数实例化另一个 Handler 类,该类为内部类。至此,就有了两个线程,各自有一个 Handler 来处理消息。3. 当调用 onXXX 的时候,在 XXX 函数内部会将请求封装成一个内部的参数
7、类,将其作为消息的参数,将此消息发送至另一个线程。4. 在该线程的 Handler 中,接受该消息,并分析传入的参数,用初始化时传入的ContentResolver 进行 XXX 操作,并返回 Cursor 或其他返回值。5. 构造一个消息,将上述返回值以及其他相关内容绑定在该消息上,发送回主线程。6. 主线程默认的 AsyncQueryHandler 类的 handleMessage 方法(可自定义,但由于都是内部类,基本没有意义.)会分析该消息,并转发给对应的 onXXXComplete 方法。7. 用户重写的 onXXXComplete 方法开始工作。这就是它偷偷摸摸做过的事情,基本还是
8、很好理解的。我唯一好奇的是它的线程管理方式,我猜测他是用的单件模式。第一个 AsyncQueryHandler 的实例化会导致创建一个线程,从此该线程成为不死老处男,所有的 ContentResolver 相关的工作,都由该线程统一完成。个人觉得这种解决方式很赞。本来这个线程的生命周期就很难估量,并且,当你有一个ContentProvider 的请求的时候,判断你会做更多的类似操作并不过分。就算错了,花费的也只是一个不死的线程(与进程同生死共存亡.) ,换来的却是简单的生命周期管理和无数次线程生死开销的节约。同时另外一个很重要的问题,他并会涉及到单件中数据同步的问题,每个类都有各自的 Handler 类,彼此互不干扰,分发可以分别进行。当多个数据请求的时候,在同一个 ContentResolver 上进行的可能微乎其微,这就避免了堵塞。总而言之,这套解决办法和 Android 的整体设计算是天作之合了。所以建议,如果你有什么非 ContentProvider 操作,却需要异步多线程执行的话,模拟一套,是个不错的策略,当然,具体情况具体分析,生搬硬套是学不好马列主义的。 。 。