Android AlarmManager

API文档解读

概述:

这个类提供了一种系统的提示服务。他允许你安排你的应用在未来某个时间点的状态。当一个闹钟开始的时候,他内部通过系统广播注册的Intent会自动启动目标的应用(如果它不在运行的话)。当设备休眠时,已经被注册的闹钟会被保留(在运行时,他可以任意唤醒设备),但是当他被关闭或者重启时他所携带的信息将被清空。

主要方法介绍

AlarmManager为系统服务,使用AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);获取AlarmManager对象。

常用的方法有三个:

  1. set(int type,long triggerAtMillis,PendingIntent operation)

单次闹钟设置。

首先看一下参数:

type: 闹钟类型

  • ELAPSED_REALTIME: 使用SystemClock.elapsedRealtime()计时(相对时间),也就是从系统启动后才开始计时的,包括睡眠时间,使用这种方式时,系统进入睡眠状态时,闹铃不会唤醒系统,直到系统下次被唤醒才传递。
  • ELAPSED_REALTIME_WAKEUP:跟上面ELAPSED_REALTIME类型相似,不同点是当系统进入睡眠状态时,闹铃依然会唤醒系统。
  • RTC:使用System.currentTimeMillis()(绝对时间)计时,当triggerAtMillis值与当前系统时间相同时,启动闹钟。当系统进入睡眠状态时,这种类型的闹铃不会唤醒系统。
  • RTC_WAKEUP:跟RTC类型类似,不同点是当系统进入睡眠状态时,这种类型的闹铃会唤醒系统。

triggerAtMillis: 闹钟开始启动的时间
operation: 闹钟开始时响应的操作,将包含触发操作的Intent封装到PendingIntent中,并将此PendingIntent当做参数传入。它的获取方式取决于实现闹钟的方式:如果你用Service启动闹钟的话,就是用Pending.getService()方式封装,同理:Broadcast对应PendingIntent.getBroadcast(),Activity对应PendingIntent.getActivity()。

  1. setRepeating(int type,long triggerAtMillis,long intervalTime,PendingIntent operation)

设置重复闹钟。

intervalTime:闹钟两次唤醒的时间间隔

  1. setInexactRepeating(int type,long triggerAtMillis,long intervalTime,PendingIntent operation)

设置不精确重复闹钟,相对于setRepeating()它更节能省电巴拉巴拉,但是间隔的时间不固定。

源码分析

无论是set()还是setRepeating()方法,最后都调用了setImpl()方法,只是传入的参数不同,调用停止在mService.set(type, triggerAtMillis, windowMillis, intervalMillis, operation,
workSource, alarmClock);
这个方法,这个mService是什么鬼,我们找到它的初始化部分:

 /**
     * package private on purpose
     */
    AlarmManager(IAlarmManager service, Context ctx) {
        mService = service;

        final int sdkVersion = ctx.getApplicationInfo().targetSdkVersion;
        mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KITKAT);
    }

原来它是IAlarmManager,因为无法查看他的内部实现,我在网上寻觅了一下,果然找到一篇关于他的介绍参考

ALMS(疯狂借鉴中)

在Android中,闹钟是由Alarm Manager Service控制的,我们调用的AlarmManager其实只是个打杂的,AlarmManager里面控制的主要是逻辑部分,然后通过调用ALMS提供的接口来完成具体的功能,ALMS的外部接口为IAlarmManager,所以具体的代码实现都是在ALMS内部的。

ALMS的接口:

interface IAlarmManager {
    void set(int type, long triggerAtTime, in PendingIntent operation);
    void setRepeating(int type, long triggerAtTime, long interval, in PendingIntent operation);
    void setInexactRepeating(int type, long triggerAtTime, long interval, in PendingIntent operation);
    void setTime(long millis);
    void setTimeZone(String zone);
    void remove(in PendingIntent operation);
}

这样的方法名是不是十分熟悉!!那么他们是怎么实现的呢?

在AlarmManagerService类中,有四个List,分别对应上文说的四种模式的闹钟,来偷个图。

五颜六色的是我们在程序中新建的各种闹钟,下面的蓝色的是Framework层对应的包含了某一种类的全部的闹钟的ArrayList。如:ArrayList中,五颜六色的为Alarm实体,蓝色的为ArrayList。

主要的方法实现:

 public void setRepeating(int type, long triggerAtTime, 
    long interval,
                         PendingIntent operation) 
{
    if (operation == null) {
        Slog.w(TAG, "set/setRepeating ignored because there is no intent");
        return;
    }
    synchronized (mLock) {
        Alarm alarm = new Alarm();
        alarm.type = type;
        alarm.when = triggerAtTime;
        alarm.repeatInterval = interval;
        alarm.operation = operation;

        // Remove this alarm if already scheduled.
        removeLocked(operation);

        if (localLOGV) Slog.v(TAG, "set: " + alarm);

        int index = addAlarmLocked(alarm);
        if (index == 0) {
            setLocked(alarm);
        }
    }
}

新建一个Alarm,将对应的参数传入,如果当前List中存在此Alarm就删除旧的,将新的Alarm通过addAlarmLocked方法添加到对应的ArrayList中。

 private int addAlarmLocked(Alarm alarm) {
    ArrayList<Alarm> alarmList = getAlarmList(alarm.type);

    int index = Collections.binarySearch(alarmList, alarm, mIncreasingTimeOrder);
    if (index < 0) {
        index = 0 - index - 1;
    }
    if (localLOGV) Slog.v(TAG, "Adding alarm " + alarm + " at " + index);
    alarmList.add(index, alarm);
    . . . . . .
    return index;
}

在addAlarmLocked方法中使用二分法进行排序,激发时间越早的将被放到前面。如果插入到第0位,就会调用setLocked更新一下对应ArrayList的最早激发时间。

在AlarmManagerService内部有一个AlarmThread线程,初始化的时候就启动这个线程。

AlarmThread新建了一个List来存储所有类型的需要激发的Alarm,即triggerList,然后遍历调用triggerList中的每个PendingIntent,然后判断一下闹钟的类型是不是唤醒类型(设备睡眠的时候是否需要唤醒),如果需要唤醒就调用BatteryStatsService内部方法进行唤醒。在AlarmManagerService内部有个变量为mBroadcastRefCount,他记录了triggerList的大小,每激活一个PendingIntent就会将mBroadcastRefCount减一,直到mBroadcastRefCount为0时就释放掉锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值