原生Calendar代码:

5.0Calendar源码.rar

提取的JavaDoc:

Calendar的javadoc.rar

1. AsyncQueryService和AsyncQueryServiceHelper。

  Calendar的主入口是AllInOneActivity,这个类实现了一个重要的接口——CalendarController.EventHandler,它的父类是AbstractCalendarActivity。

  先来看AbstractCalendarActivity,它是AllInOneActivity, EditEventActivity, SelectVisibleCalendarsActivity这三个类的父类。其内容很简单:

public abstract class AbstractCalendarActivity extends Activity {
protected AsyncQueryService mService; public synchronized AsyncQueryService getAsyncQueryService() {
if (mService == null) {
mService = new AsyncQueryService(this);
}
return mService;
}
}

  包含一个AsyncQueryService变量和对应的get方法,并且get方法还是加锁的,保证了AsyncQueryService对象的唯一性。

  那么这个AsyncQueryService对象是干什么用的?从名字可以看出,这是一个“异步查询服务”,但它并不继承自Service,而是继承自Handler。这个类的注释很详细,总结如下:

  • 这是一个辅助类,是用来在后台Service中执行ContentResolver调用的。它将因为调用方(活动)被杀而导致调用丢失的可能性降至最低。
  • 它被设计用来将AsyncQueryHandler在后台线程调用ContentResolver的方式简单的迁移到Calendar中。
  • 这个类支持增删改查和批量操作,它也支持延迟处理和时限内取消操作。注意一个应用中只有一个队列来序列化所有调用。

  上面说了,本质上AsyncQueryService是个Handler,但它又要在后台Service中执行操作,这个Service就是AsyncQueryServiceHelper,AsyncQueryServiceHelper是IntentService的子类。

  所以,AsyncQueryService的基本操作模式是,外部调用其添删改查方法时,它把方法参数和自身的引用交给一个IntentService,由这个IntentService来实际执行添删改查操作。执行完后,IntentSerice会给Handler回送消息。而在AsyncQueryService的handlerMessage中,它会根据操作类别回调不同的方法,例如onDeleteComplete。

  因此,在使用AsyncQueryService时,我们需要实现自己的子类,重写onDeleteComplete等方法,就可以实现自动在后台服务中做数据操作,操作结束后在主线程回调操作结果。

  注意一点,上面的AbstractCalendarActivity中的AsyncQueryService对象是直接实例化的,没有重写任何回调方法。因为这个对象只在EditEventHelper中用到了:

public EditEventHelper(Context context) {
mService = ((AbstractCalendarActivity)context).getAsyncQueryService();
}
mService.startBatch(mService.getNextToken(), null, android.provider.CalendarContract.AUTHORITY, ops,
Utils.UNDO_DELAY);

只需要编辑后台数据,无需回调显示到视图上。

  AsyncQueryService的结构并不复杂,但其中有一些细节值得学习:

  1. 使用AtomicInteger类和它的getAndIncrement方法,获得数据操作的token。关于原子操作的介绍见Java 理论与实践: 流行的原子

  2. AsyncQueryService传递给AsyncQueryServiceHelper的Handler引用没有直接用this,而是用的mHander,便于测试。

    private Handler mHandler = this; // can be overridden for testing

    // @VisibleForTesting

    protected void setTestHandler(Handler handler) {

    mHandler = handler;

    }

  3. AsyncQueryServiceHelper实例化了一个静态常量的队列来存储数据操作信息,因此这个队列对于应用是唯一的。注意这里使用了PriorityQueue,它会按操作的计划时间来自动对其排序,这是因为OperationInfo类实现了Comparable接口。

  4. 后台查询得到Cursor对象后,主动调用了一次cursor.getCount()方法,这样可以让主线程中对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, e.toString());
    cursor = null;
    }

Android原生Calendar代码阅读(一)的更多相关文章

  1. Android 上的代码阅读器 CoderBrowserHD 修改支持 go 语言代码

    我在Android上的代码阅读器用的是 https://github.com/zerob13/CoderBrowserHD 改造的版本,改造后的版本我放在 https://github.com/ghj ...

  2. PhoneGap或者Cordova框架下实现Html5中JS调用Android原生代码

    PhoneGap或者Cordova框架下实现Html5中JS调用Android原生代码 看看新闻网>看引擎>开源产品 0人收藏此文章, 发表于8小时前(2013-09-06 00:39) ...

  3. 像写Flutter一样开发Android原生应用

    要问到Flutter和Android原生App,在开发是有何区别,编程方式是绕不开的话题.Flutter采用声明式编程,Android原生开发则采用命令式编程. 声明式编程 VS. 命令式编程 我们首 ...

  4. 《Android原生整合虹软SDK开发uniapp插件》

    1.项目背景 应公司要求,需要开发一套类似人脸打卡功能的app,但是因为我们公司没有很强的原生android开发者,所以根据现状选择了第三方跨平台的uniapp,想必目前大多人都了解这个平台了,我也就 ...

  5. 拓展 Android 原生 CountDownTimer 倒计时

    拓展 Android 原生 CountDownTimer 倒计时 [TOC] CountDownTimer 在系统的CountDownTimer上进行的修改,主要是拓展了功能,当然也保留了系统默认的模 ...

  6. Android原生游戏开发:使用JustWeEngine开发微信打飞机

    使用JustWeEngine开发微信打飞机: 作者博客: 博客园 引擎地址:JustWeEngine 示例代码:EngineDemo JustWeEngine? JustWeEngine是托管在Git ...

  7. Android+Sqlite 实现古诗阅读应用(三)

    往期传送门: Android+Sqlite 实现古诗阅读应用(一) Android+Sqlite 实现古诗阅读应用(二) 加入截图分享的功能. 很多应用都有分享的功能,我也想在我的古诗App里加入这个 ...

  8. Android+Sqlite 实现古诗阅读应用(二)

    传送门:Android+Sqlite 实现古诗阅读应用(一) Hi,又回来了,最近接到很多热情洋溢的小伙伴们的来信,吼开心哈,我会继续努力的=-=! 上回的东西我们做到了有个textview能随机选择 ...

  9. [Android Pro] android 4.4 Android原生权限管理:AppOps

    reference : http://m.blog.csdn.net/blog/langzxz/45308199 reference : http://blog.csdn.net/hyhyl1990/ ...

随机推荐

  1. C#方法的重载

    方法的重载 参数不同,个数可以相同 参数相同,个数不能相同 static void Main(string[] arr) { Console.WriteLine(M(,)); Console.Read ...

  2. zoj 3755

    状态压缩dp 扫雷 n×M格子奇数行有雷,给出偶数行的数字,求最少有多少个雷. 刚开始觉得状压状态不知道怎么办,因为每行能影响的范围太广,后来展昭说横着来,然后几分钟就a了. 这件事请告诉我们看问题要 ...

  3. MySQL 忘记密码后的重置操作

    一.修改配置文件方式        1.关闭 MySQL                 linux:                        1)service mysqld stop     ...

  4. GO的MAP字典简单用法示例

    package main import "fmt" type PersonInfo struct { ID string Name string Address string } ...

  5. 防止DC电源反接的方法——SS14的用法

    出处:http://blog.ednchina.com/tengjingshu 电源是PCB板的重要部分,每个芯片都需要电源供给.芯片其实是挺脆弱的,只要正负接反得话,大多数就会挂掉,相信很多人都有惨 ...

  6. Mysql unix_timestamp() FROM_UNIXTIME和DATE_FORMAT(date,format)

    mysql 中:UNIX_TIMESTAMP(), UNIX_TIMESTAMP(date) 若无参数调用,则返回一个 Unix timestamp ('1970-01-01 00:00:00' GM ...

  7. mv command:unable to remove target: Is a director

    mv command:unable to remove target: Is a director This is somewhat simple as long as we understand t ...

  8. BZOJ2697: 特技飞行

    2697: 特技飞行 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 607  Solved: 363[Submit][Status] Descript ...

  9. glibc的了解,对内核的封装

    glibc除了提供最底层的C运行库,还封装了kernel提供的API,程序通过glibc进行系统调用( syscall). 应用层面的C库,比如OpenSSL库: /usr/include/opens ...

  10. 程序员必备基础知识:通信协议——Http、TCP、UDP

    CP HTTP UDP: 都是通信协议,也就是通信时所遵守的规则,只有双方按照这个规则“说话”,对方才能理解或为之服务. TCP HTTP UDP三者的关系: TCP/IP是个协议组,可分为四个层次: ...