Android Alarm学习笔记
- 格式:docx
- 大小:14.97 KB
- 文档页数:2
Android Framework核心知识点汇总手册是Android开发人员必备的参考资料,它详细介绍了Android操作系统的工作原理和核心组件。
手册首先概述了Android的系统架构,包括应用程序层、应用程序框架层、系统服务和系统库等。
核心知识点包括活动(Activity)、服务(Service)、广播接收器(BroadcastReceiver)和内容提供者(ContentProvider)等组件的使用方法和最佳实践。
此外,手册还深入介绍了Android的消息传递机制、事件处理机制、资源管理系统以及安全性和权限管理等方面的知识。
通过学习这本手册,Android开发人员可以深入了解Android框架的工作原理,掌握各种组件的使用方法和最佳实践,提高开发效率和应用性能。
同时,手册还提供了丰富的示例和练习题,帮助读者更好地理解和应用所学知识。
总之,Android Framework核心知识点汇总手册是Android开发人员必备的参考资料,它有助于提高开发人员的技能水平和应用性能,为开发出高效、稳定的Android应用程序提供了有力支持。
Android 4.0 Alarm机制浅析Author: VIC.LUO@最近在做关于Alarm的一些东西,所以就把Android平台上的alarm的源代码给稍微看了看。
我个人其实基本不写文档的,而且即使写,也不过区区数字,这个应该是我工作4年来的第二篇文档(第一篇是写的和我一直以来工作相关的Messaging)所以内容上和排版上大家就不要见怪。
Android系统中alarm机制最大的体现着就是闹钟这个app了。
通过这个应用我们可以设置自己的各种定时闹钟,当然系统中的各种定时相关功能的实现也基本全部依赖Alarm机制。
闹钟的代码在packages\apps\DeskClock\src\com\android\deskclock目录下,可以自行查看,这里主要说的是Alarm机制。
Alarm机制实现的代码主要在./frameworks/base/core/java/android/app/AlarmManager.java./frameworks/base/services/java/com/android/server/AlarmManagerService.java./frameworks/base/services/jni/com_android_server_AlarmManagerService.cpp再往下就是驱动和kernel的代码,个人对驱动和kernel的代码不了解,就不说了。
AlarmManager是framework中提供给用户来使用的API,其实现在AlarmManagerService,为一个server,通过binder机制来提供服务,开机便注册到system_server进程中(所有server实现基本都如此)代码如下(systemserver.java)alarm = new AlarmManagerService(context);ServiceManager.addService(Context.ALARM_SERVICE, alarm);下面就来介绍一下AlarmManagerService,本来想用ams代替,不过一般情况下ams指的是ActivityManagerService,所以也就罢了。
Android中Alarm的机制本次给大家分析的是Android中Alarm的机制所用源码为最新的Android4.4.4。
首先简单介绍如何使用Alarm并给出其工作原理,接着分析Alarm和Timer以及Handler在完成定时任务上的差别,最后分析Alarm机制的源码。
什么是AlarmAlarm是android提供的用于完成闹钟式定时任务的类,系统通过AlarmManager来管理所有的Alarm,Alarm支持一次性定时任务和循环定时任务,它的使用方式很简单,这里不多做介绍,只给出一个简单的示例:[java]view plaincopyAlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(getApplicationContext(), TestActivity.class); PendingIntent pendIntent =PendingIntent.getActivity(getApplicationContext(),0, intent, PendingIntent.FLAG_UPDATE_CURRENT); //5秒后发送广播,只发送一次int triggerAtTime = SystemClock.elapsedRealtime() + 5 * 1000;alarmMgr.set(AlarmManager.ELAPSED_REALTIME, triggerAtTime, pendIntent); Alarm和Timer以及Handler在定时任务上的区别相同点:三者都可以完成定时任务,都支持一次性定时和循环定时(注:Handler可以间接支持循环定时任务)不同点:Handler和Timer在定时上是类似的,二者在系统休眠的情况下无法正常工作,定时任务不会按时触发。
alarm()函数的使⽤总结alarm()函数说明1.引⽤头⽂件:#include <unistd.h>;2.函数标准式:unsigned int alarm(unsigned int seconds);3.功能与作⽤:alarm()函数的主要功能是设置信号传送闹钟,即⽤来设置信号SIGALRM在经过参数seconds秒数后发送给⽬前的进程。
如果未设置信号SIGALARM的处理函数,那么alarm()默认处理终⽌进程。
4.函数返回值:如果在seconds秒内再次调⽤了alarm函数设置了新的闹钟,则后⾯定时器的设置将覆盖前⾯的设置,即之前设置的秒数被新的闹钟时间取代;当参数seconds为0时,之前设置的定时器闹钟将被取消,并将剩下的时间返回。
alarm()测试1.1#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>void sig_handler(int num){printf("receive the signal %d.\n", num);}int main(){signal(SIGALRM, sig_handler); //SIGALRM是在定时器终⽌时发送给进程的信号alarm(2);pause();//pause()函数使该进程暂停让出CPUexit(0);} 运⾏结果:两秒钟后输出如果我们想程序每2秒都定时⼀下,这样实现也很简单,我们在处理定时信号的函数中再次定时2秒;实例如下:#include<stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>void sig_handler(int num){printf("receive the signal %d.\n", num);alarm(2);}int main(){signal(SIGALRM, sig_handler);alarm(2);while(1)//做⼀个死循环,防⽌主线程提早退出,相等于线程中的join{pause();}//pause();//如果没有做⼀个死循环则只会让出⼀次cpu然后就还给主线程,主线程⼀旦运⾏结束就会退出程序exit(0);}运⾏结果:每隔2秒钟就会输出⼀次。
第一行代码知识点总结1、Android四层架构:Linux内核层(提供底层驱动)、系统运行库层(提供特性支持,一些核心库)、应用框架层(提供各种API)和应用层2、Android四大组件:活动(activity)、服务(Service)、广播接收器(Broadcast Receiver)和内容提供器(Content Provider)3、Android应用特色开发:四大组件、丰富的系统控件、SQL数据库(轻量级,运算速度快的嵌入式关系型数据库)、强大的多媒体和地理位置定位(LBS)。
4、Android程序设计讲究逻辑和视图分离,通常在布局文件中编写在界面4.1Android的日志工具Log:Log.d()打印调试信息对应debug。
Log.v()打印琐碎、意义最小日志,对应verbose,Log.i()打印比较重要的数据对应info;Log.w()打印警告信息对应error;Log.e()打印错误信息对应error。
Log.d(类名,打印内容)4.2活动:主要用于和用户进行交互、基本用法4.3活动中的提醒方式Toast4.4、drawable存放图片,mipmap存放应用图标,values放字符串、样式,颜色等配置,layout放布局文件4.5、Android Studio是采用Gradle来构建项目5、Intent的使用:显式Intent和隐式Intent()6、活动的生命周期7、返回栈的定义8、Android是使用任务来管理活动的9、活动状态:运行、暂停、停止、销毁状态10、Activity类中的七个回调方法:onCreate()onStaart()、onResume()、onPause()、onStop()、onDestroy()和onRestart()11、活动的三种生存期:完整、可见、前台12、活动的四种启动模式:standard、singleTop、singleTask 和singleInstance13、常用控件:TextView、Button、EditText、ImageView、ProgressBar(进度条)、AlertDialog(对话框)、ProgressDialog (显示对话框时出现进度条)14、基本布局:线性布局(LinearLayout)、相对布局(RelativeLayout)、帧布局(FrameLayout)百分比布局、AbsoluteLayout、TableLayout15、常用和最难用的控件ListView16、滚动控件:RecyclerView17、碎片的定义、使用方式、碎片的生命周期、状态和回调18、广播主要的两种类型:标准广播和有序广播;注册广播的方式:静态注册和动态注册;广播接收器继承BroadcastReceiver19、本地广播(LocalBroadcastManager)20、Android系统中三种数据持久化方式:文件储存、SharedPreference储存及数据库储存,还有保存在手机SD卡中21、SQliteOpenHelper帮助类:SQliteOpenHelper中有两个抽象方法onCreate()和onUpgrade();两种重要的实例方法getReadableDatabase()和getWritableDatabase()22、LitePal操作数据库23、跨程序共享数据:内容提供器24、ContentResolver的基本用法:ContentResolver类、ContentResolver中提供给了一系列的方法用于对数据进行CRUD操作包括增删改查操作;ContentResolver增删改查方法不接收表名参数,而是用Uri参数代替。
android移动应用开发技术课第一章笔记第一章:Android移动应用开发技术课笔记一、引言在当今移动互联网时代,Android系统以其开放性和普及率成为了最受欢迎的移动操作系统之一。
随着移动应用市场的不断扩大,对Android移动应用开发技术的需求也日益增加。
学习和掌握Android移动应用开发技术成为了越来越多人的选择。
二、Android移动应用开发技术概述1. 什么是Android?Android是一款基于Linux操作系统的开源移动设备操作系统,主要用于触摸屏移动设备,如智能手机和平板电脑。
Android操作系统的开放性使得开发者可以自由定制和开发应用,受到了广大用户的喜爱。
2. Android移动应用开发技术的重要性随着信息化和数字化的发展,移动应用成为了人们获取信息和进行交流的重要方式。
而Android作为最主流的移动操作系统之一,其应用的开发和推广具有巨大的市场潜力和商业价值。
掌握Android移动应用开发技术成为了许多开发者和从业者的追求目标。
三、学习Android移动应用开发技术的重要性1. 对于个人的意义学习Android移动应用开发技术可以提升个人的职业技能,并且在移动应用开发领域有更多的发展机会。
可以通过开发自己的应用来实现个人价值和创造财富。
2. 对于企业的意义随着移动互联网的发展,各类企业都希望拥有自己的移动应用,以提升品牌形象和服务用户。
懂得Android移动应用开发技术的人才对企业来说显得格外宝贵。
四、学习Android移动应用开发技术的途径1. 自学通过阅读相关书籍、网上教程和参加线上培训班,可以自学Android 移动应用开发技术。
这种方式需要具备较好的自学能力和毅力。
2. 参加培训班选择权威的培训机构进行系统的学习和培训,可以更快速、系统地学习Android移动应用开发技术。
五、Android移动应用开发技术的未来发展随着人工智能、物联网、区块链等技术的不断发展,Android移动应用开发技术也将不断拓展应用场景和技术深度。
android alarmmanager 用法Android中的AlarmManager是一个用于调度延迟执行或重复执行任务的系统级类。
它可以在指定的时间间隔内执行某个任务或者在特定的日期和时间触发某个任务。
本文将详细介绍AlarmManager的用法,包括如何创建、设置和取消闹钟任务。
一、什么是AlarmManager?Android的AlarmManager是一个系统级别的管理器,用于调度延迟执行或重复执行任务。
它是Android系统中的一个重要部分,可以被应用程序用于一些关键任务,如定时更新数据、触发通知、执行后台操作等。
二、AlarmManager的工作原理AlarmManager使用系统的闹钟服务来调度任务。
当一个任务被设定后,AlarmManager将会启动一个定时器,当定时器到达指定时刻后,系统将会触发相应的操作。
这个操作可以是启动一个服务、发送广播或者唤醒设备等。
三、创建一个闹钟任务要创建一个闹钟任务,首先需要获取AlarmManager的实例。
可以通过如下代码来获取:AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);四、设置一个闹钟任务设置一个闹钟任务需要指定触发时间和任务的触发方式。
Android中提供了三种触发方式:1. ELAPSED_REALTIME:相对时间触发,以系统启动开始计时。
可以使用如下代码来设置:alarmManager.set(AlarmManager.ELAPSED_REALTIME, triggerTime, pendingIntent);其中,triggerTime为触发时间,pendingIntent是一个准备要触发的操作的PendingIntent对象。
2. RTC:绝对时间触发,以1970年1月1日开始计时。
可以使用如下代码来设置:alarmManager.set(AlarmManager.RTC, triggerTime, pendingIntent);3. RTC_WAKEUP:在设备处于休眠状态时,使用绝对时间触发。
Android_alarm 学习总结Android手机上的提醒服务有很多种类:闹钟,应用的定时更新,日程提醒,时间显示等等,这些不同的服务被划分成不同的类型,用应用将相应的时间和类型下发到底层,底层来管理这些下发下来的服务,并根据应用发来的消息实时更新处理;一、alarm设备的初始化1)第一个初始化函数__init alarm_dev_init(void)Alarm-dev.c中声明了static int __init alarm_dev_init(void) 这个函数用来初始化各个类型的alarm定时器;在kernel中很多函数前都会有__init,被__init标识的函数,存放在一个队列中,在系统启动时,会调用这个队列,执行被__init标识的函数;首先看下alarm_dev_init 这个函数,该函数完成了两个功能:一个是注册misc设备二是对各个类型的alarm设备进行初始化这里为每个类型的alarm设备初始化了结构体struct alarm。
这个定义在android_alarm.h中alarm_triggered作为alarm设备时间到期的回调函数实现如下:①Alarm_triggered所传入的参数即初始化alarm设备时每个类型的设备所对应的struct alarm;因此步骤①是为了获取触发alarm_truggered的alarm设备的mask;②这里判断触发alarm_triggered回调函数的alarm设备是否被使能(用户是否使能了这个闹铃;用户是否使能了这个日程提醒服务;软件更新题型服务是否被打开)alarm_enabled这个全局量用来标记alarm设备是否被使能;使能它的地方在当我们从ui界面设置一些不同类型的alarm服务的时候,与其类型相对应的mask值会被赋给alarm_enabled这个全局量;例如,如果上层应用下发的alarm设备有三种,其type值分别为1,2,3,那么其mask值分别为10,100,1000.这样根据alarm_enable的每一位是否为1,就可以判断出其对应的alarm设备是否被使能;③与from_old_alarm_set里使能标志位对应,这里的操作清除了该标志位的mask值,对于已经触发回调函数的alarm设备,其状态应该从使能变成禁止,等待下次使能;同样在清除闹钟时也会禁止alarm设备使能标志位;④Alarm_pending 这个全局量也用来存储各个类型alarm设备的mask值,当某一类型的alarm触发其回调函数时,表示这类alarm到期了,因此将这类alarm设备对应的mask值赋给alarm_pending,当上层得知这类alarm到期后,alarm_pending的值被清掉;简单的说alarm_pending 的作用就是将底层到期的alarm事件告知上层;⑤Wake_lock_timeout(&alarm_wake_lock,5*HZ)该操作是给系统加5秒的alarm_wake_lock锁,即当前有alarm设备到期,需要触发上层应用,此时不允许系统休眠;关于alarm_triggered回调函数:代码里的注释说这个function是alarm结构体的回调函数,但仔细看看就能发现,alarm结构体不具备调用这个回调函数的条件,简单的说alarm设备在底层被初始化成定时器,而android_alarm.h中声明的struct alarm里没有定时器相关信息,而从函数alarm_dev_init(void)初始化到现在也没看见任何起定时器的地方,因此struct alarm.function是当alarm设备的时间到期时,会从别的地方调用过来,层层调用到alarm_triggered这个函数;看到这里alarm设备对上层的接口是初始化完成了,可以确定的是alarm到期时,也是通过alarm_triggered将alarm.type相对应的mask值写入alarm_pending中,给上层查询;2)第二个初始化函数__init alarm_driver_init(void)同样作为__init函数,在内核初始化后会被自动执行;①:Hrtimer_init的第一个参数timer 即struct alarm_queue.timer;hrtimer timer 定义在kernel\include\linux 中这里的初始化工作相当于为每个类型的alarm 设备初始化其相应的定时器,timer 作为alarm 设备的初始化信息,包括了expires time 、timer.function 、rb_node ;初始化了定时器,注册了回调函数;那么这里的time.function 应该就是alarm 定时器到期时所调用的回调函数了;② :注册回调函数alarm_timer_triggered ;①:判断当前定时器是否已经停止;若停止,将定时器停止时的stop_time赋值给now,若没停止,则获取系统当前的时间,赋值给now,②:若alarm的到期时间还在now时间之前,break,③:判断满足条件后,对维护alarm定时器的红黑树进行操作,删除掉过期的节点,保持first指针指向最先到期的节点;④:之后调用struct alarm.function,这个function被第一个初始化函数__init alarm_dev_init(void)初始化成alarm_triggered();由此可见,第二个初始化函数完成了alarm底层定时器的初始化操作,并且注册了回调函数alarm_timer_triggered(),在定时器到期后,回调函数会调用alarm_triggered;将到期的alarm设备的mask值写入alarm_pending,给上层查询;各种类型的alarm(提醒)服务被按类型初始化成定时器;alarm_dev_init的作用就是针对每一类型的alarm服务初始化其对应的定时器hrtimer_init;kernel管理这些定时器来确定当前的alarm是否到期;二、设置alarm服务Alarm服务的设置都是通过调用AlarmManagerService.java里的set方法将相应的时间和alarm的类型设置到kernel中;Type即我们设置的alarm类型,在kernel里有不止一种的alarm type的类型,闹钟服务只是其中的一种,因此在设置闹钟时间时,需要匹配对应的type;alarmSeconds即平台层需要下发的时间了;在android中java和c之间还有一个jni层,用来将java的方法与kernel的操作联系起来;和闹钟有关的jni操作在com_android_server_AlarmMangerService.cpp中;包括init,和set的方法都在这里与cpp对应起来了,因此调用set方法就会调用到jni的相应函数,在函数android_server_AlarmManagerService_set()中会有如下调用:①:ioctl(fd,ANDROID_ALARM_SET(type),&ts);&ts结构体包括了设置的闹铃时间;ANDROID_ALARM_SET(type)就是设置闹钟的命令了;这个ioctl的操作在java中init方法中匹配上的:open(“/dev/alarm”,O_RDWR);因此set方法调用的ioctl操作就会对应到/dev/alarm注册的ioctl操作;这个操作是在alarm-dev.c中注册的;此时用户通过APK设置的闹钟时间和设置闹钟的操作就传到了kernel层;②在alarm-dev.c中设置alarm类型会对应到alarm_ioctl中的case ANDROID_ALARM_SET;①:alarm_start_range将用户空间得到的时间更新到ktime定时器中;该函数的第一个参数&alarms[alarm_type]是第一个初始化函数__initalarm_dev_init(void)中初始化的结构体struct alarm;第二个参数和第三个参数一样,是时间参数;①:这个函数更新的是struct alarm中的时间变量softexpires和expires,这两个成员被初始化成相同的值;这样一个alarm设备就设置完成了;这个时间被作为该alarm设备定时器到期的时间,在到期后调用回调函数alarm_timer_triggered()-- alarm_triggered();关于alarm定时器时间的更新:从上边的流程可以看到ui界面设置一个alarm服务,在kernel只会更新到结构体struct alarm,但该结构体并没有和定时器相关的信息,而成员变量softexpires和expires何时被赋值给ktime定时器的?这个是通过struct alarm中成员rb node node来实现的;底层所有的alarm定时器都被维护成一个红黑树,那么每个类型alarm设备对应的红黑树的节点号也是可查询的;Struct hrtimer维护了相应红黑树节点定时器的信息,因此struct alarm通过更新相应node的成员信息,就可以更新到hrtimer结构体中定时器的到期时间了;三、查询alarm是否到期底层驱动在alarm设备到期后只会将alarm type mask的值赋给alarm_pending,而上层是通过不断轮询alarm pending判断哪种类型的alarm到期了;Alarm thread任务起来后,会一直调用函数waitforalarm(mDescriptor);该函数在jni层被匹配成;因此该服务对应到kernel就是alarm_ioctl会被一直调用,命令为android_alarm_wait;①:将alarm_pending的值赋给rv,rv作为alarm_ioctl的返回值;因此当alarm_triggered被触发时,alarm_pending就会被赋予相应的mask值;所以当上层发命令轮询时,这个alarm_pending的值就会被当成返回值返回;result = waitforalarm(mDescriptor);result的值就是alarm_pending 的值;在获取到相应alarm_pending的值后,开始和上层alarm服务的mask值相匹配:①若result的值匹配到poweroff_wakeup_mask 上层就知道了此时闹钟到期了,就会调用相关的apk提醒用户;Nv关机闹钟补丁分析大多数的网站上都在说android手机不支持关机闹钟,关机闹钟的部分接口,调用需要根据具体的pmic芯片资料进行添加;添加后是可以支持的;Oscar项目使用tps6586x pmic芯片,该芯片支持rtc中断进行系统唤醒;因此在此项目上可以实现关机闹铃;NV的工程师给我们提供了支持关机闹钟的补丁,里边的修改如下:1)tps6586x_rtc_probe- /* 1 kHz tick mode, enable tick counting */+ /* 1 kHz tick mode, enable tick counting,+ enable power off alarm.+ */err = tps6586x_update(tps_dev, RTC_CTRL,- RTC_ENABLE | OSC_SRC_SEL | ((pdata->cl_sel << CL_SEL_POS) &- CL_SEL_MASK),- RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK);+ RTC_ENABLE | OSC_SRC_SEL | RTC_RSVDC00 |+ ((pdata->cl_sel << CL_SEL_POS) & CL_SEL_MASK),+ RTC_ENABLE | OSC_SRC_SEL | RTC_RSVDC00 | PRE_BYPASS | CL_SEL_MASK);Proc函数中的修改如NV补丁中的log所示,增加了使能power off alarm的操作;tps6586x_updata(dev,reg,val,mask);由此可见此函数的第三个参数是用来写rtc_ctrl寄存器的值,其中:#define RTC_RSVDC00 BIT(0) 即1<<0;……同理可以计算出其他位寄存器的值;这里可以确定rtc_ctl寄存器里B0位值为1:使能RTC_ALARM2寄存器;这组寄存器可以产生唤醒系统的中断;B3位为0;rtc_count的计数频率为1KHZ;即1024次计数为1秒;这里可以对比下tps6586x中关于rtc寄存器的说明:2)tps6586x_rtc_set_alarm该函数将从kernel传下来的闹钟时间与系统时间进行比较,并计算出差值ticks,若差值大于0;那么将ticks设置到rtc_alarm寄存器里;NV给的补丁修改了设置的寄存器:- err = tps6586x_writes(tps_dev, RTC_ALARM1_HI, sizeof(buff), buff);+ err = tps6586x_writes(tps_dev, RTC_ALARM2_HI, sizeof(buff), buff);这里询问了NV的工程师,他们给出的答复如下:Only RTC_ALARM2 can automatically wake the PMU from the SLEEP state once the RTC_COUNT value equals the value stored in the RTC_ALARM2 Registers因此设置关机闹钟应该将ticks写入到rtc_alarm2寄存器中;函数tps6586x_writes将从RTC_ALARM2_Hi的高地址开始写入buff里所存储的ticks 值;这里的ticks值经过如下换算存入buff:+ buff[0] = (ticks >> 8) & 0xff;+ buff[1] = ticks & 0xff;可见存入buff的值也是从高位开始的;还有一点需要说明:ticks的值在计算过程中经过了这样的操作:ticks = (unsigned long long)seconds << 10;......ticks >>= 12换算成二进制后,最后两位被遗弃了:这里可以参照下NV补丁中的注释:/*+ TPS658621C datasheet update:+ ALM2[15:0] is compared to RTC[27:12] regardless if the+ pre-scaler is enabled or disabled.+ */ALM2寄存器一共16位,它会和COUNT的[27:12]位进行比较,这里有个地方需要注意下,由于从第10位开始就是每秒递增计数了,而ALM2寄存器比较是从count的12位开始的,因此在将ticks的值写入ALM2的时候会舍弃2位;也就有了如上的移位操作了;舍弃了低2位的秒数,这样会带来3秒的比较误差;RTC中断的产生会提前3秒;这样是否有影响?RTC_ALARM中断是用来在关机时唤醒系统的,并且在唤醒后将此次RTC开机事件报给上层,由上层调用闹钟的相关APK,来使能闹铃;这么一个开机启动闹铃的过程本来就需要耗费时间;因此提前了3秒产生中断也刚好在开机的过程中弥补掉了;这样ALM2寄存器的16位可以表示到2^16<<2 大约是72.8hours 即ticks_max=72.8hours通过以上修改,使能了ALM2寄存器,确定了计数频率,这样在设置闹钟的时候就可以把闹铃时间设置到RTC寄存器中,从而在时间到时产生可以唤醒系统的中断;。
设置一个Alarm需要更新一下数据。
1. update alarms.db
2. update com.android.alarmclock_preferences.xml
3. update Settings.System.NEXT_ALARM_FORMATTED for status bar
4. set Kernel RTC alarm or send a message if no driver
具体的函数调用如下所示:
com.android.alarmclock.AlarmClock.onCreate() -> SetAlarm.onPreferenceTreeClick() -> SetAlarm.saveAlarm() ->
Alarm.setAlarm() -> Alarm.setNextAlert() -> Alarm.enableAlert(ALARM_ALERT_ACTION)/saveNextAlarm(Settings.System.NEXT _ALARM_FORMATTED) ->
android.app.AlarmManager.set() -> AlarmManagerService.set() -> AlarmManagerService.setRepeating -> AlarmManagerService.setLocked() -> android.app.IAlarmManager.set() -> RTC.save()// /dev/alarms
Alarm闹铃的函数调用如下所示:
RTC (WAKEUP) -> AlarmReceiver.onReceive(ALARM_ALERT_ACTION) -> AlarmAlert.onCreate() ->
AlarmAlertWakeLock.acquire()/KeyguardManager.newKeyguardLock().disableKeyg uard() ->
AlarmKlaxon.postPlay() -> AlarmKlaxon.KillerCallback().onKilled() -> AlarmAlert.dismiss() ->
AlarmAlertWakeLock.release()/KeyguardManager.newKeyguardLock().reenableKey guard()
DeskClock App中的code block说明如下:
Alarm是描述闹钟的抽象类。
AlarmAlert处理闹铃过程中系统相关的事件,继承AlarmAlertFullScreen。
AlarmAlertFullScreen显示闹铃界面,并处理闹钟界面上到控件消息。
AlarmAlertWakeLock提供控制wakelock接口。
AlarmClock闹钟界面,包括闹钟列表、数字时钟、option菜单。
AlarmKlaxon是一个服务,提供闹铃和震动功能,如果一个闹铃fire,前面一个闹铃已经在闹来,则取消前面那个,闹后来者。
AlarmPreference闹铃文件。
ContentProvider维护闹钟表,字段包括_id、hour、minutes、daysofweek、alarmtime、enabled、vibrate、message、alert。
Alarms提供了操作闹钟的接口,相当于AlarmManager。
enableAlert()设置一个闹钟,用的是PendingIntent到方式计算时间。
RTC的设置在enableAlert()的am.set(AlarmManager.RTC_WAKEUP, atTimeInMillis, sender); RTC_WAKEUP表示该Alarm如果在关机的情况下来到,则会自动开机闹铃。
DeskClock桌面时钟到activity。
其中包括了系统时间、日期、电池及天气等信息,其中天气信息是判断是否存在提供天气信息的app后,从数据库中读取当前的天气信息来更新。
也就
是天气APP只需要更新数据库中的天气信息即可。
DigitalClock维护数字时钟。
HandleSetAlarm设置alarm到activity。
Framework相关的code block如下:
AlarmManager和AlarmManagerService,这两个文件组成了AlarmService。
关于PendingIntent:
PendingIntent就是一个Intent的描述,我们可以把这个描述交给别的程序,别的程序根据这个描述在后面的别的时间做你安排做的事情(By giving a PendingIntent to another application, you are granting it the right to perform the operation you have specified as if the other application was yourself,就相当于PendingIntent代表了Intent)。
本例中别的程序就是发送短信的程序,短信发送成功后要把intent广播出去。