AlarmManager后台一直周期性的执行(解决API大于19的问题)

需求:需要app在后台一直记录当前位置坐标,5s上传服务器一次,app退出依然执行。
分析:根据需求,决定使用AlarmManager+pendingIntent启动一个service,后台记录当前坐标。

AlarmManager:

概念:

AlarmManager是一个全局的定时器,是Android中常用的一种系统级别的提示服务,在指定时间或周期性启动其它组件(包括Activity,Service,BroadcastReceiver)。

常用方法:

(1)set(int type,long startTime,PendingIntent pi);

该方法用于设置一次性闹钟,第一个参数表示闹钟类型,第二个参数表示闹钟执行时间,第三个参数表示闹钟响应动作。

(2)setRepeating(int type,long startTime,long intervalTime,PendingIntent pi);

该方法用于设置重复闹钟,第一个参数表示闹钟类型,第二个参数表示闹钟首次执行时间,第三个参数表示闹钟两次执行的间隔时间,第三个参数表示闹钟响应动作。

(3)setInexactRepeating(int type,long startTime,long intervalTime,PendingIntent pi);

该方法也用于设置重复闹钟,与第二个方法相似,不过其两个闹钟执行的间隔时间不是固定的而已。间不是固定的而已。

(4)setWindow(int type, long windowStartMillis, long windowLengthMillis, PendingIntent operation)
该方法是针对API>=19使用,因为API>19之后,android平台为了省电机制,setRepeating()已经不再准确
参数和setRepeating的参数大致类似。

参数详解:

type类型:

闹钟的类型,常用的有5个值:AlarmManager.ELAPSED_REALTIME、 AlarmManager.ELAPSED_REALTIME_WAKEUP、AlarmManager.RTC、 AlarmManager.RTC_WAKEUP、AlarmManager.POWER_OFF_WAKEUP。

AlarmManager.ELAPSED_REALTIME表示闹钟在手机睡眠状态下不可用,该状态下闹钟使用相对时间(相对于系统启动开始),状态值为3;

AlarmManager.ELAPSED_REALTIME_WAKEUP表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟也使用相对时间,状态值为2;

AlarmManager.RTC表示闹钟在睡眠状态下不可用,该状态下闹钟使用绝对时间,即当前系统时间,状态值为1;

AlarmManager.RTC_WAKEUP表示闹钟在睡眠状态下会唤醒系统并执行提示功能,该状态下闹钟使用绝对时间,状态值为0;

AlarmManager.POWER_OFF_WAKEUP表示闹钟在手机关机状态下也能正常进行提示功能,所以是5个状态中用的最多的状态之一,该状态下闹钟也是用绝对时间,状态值为4;不过本状态好像受SDK版本影响,某些版本并不支持;

long startTime:

闹钟的第一次执行时间,以毫秒为单位,可以自定义时间,不过一般使用当前时间。需要注意的是,本属性与第一个属性(type)密切相关。
如果第一个参数对应的闹钟使用的是相对时间(ELAPSED_REALTIME,ELAPSED_REALTIME_WAKEUP),那么本属性就得使用相对时间(相对于 系统启动时间来说),比如当前时间就表示为:SystemClock.elapsedRealtime();
如果第一个参数对应的闹钟使用的是绝对时间 (RTC、RTC_WAKEUP、POWER_OFF_WAKEUP),那么本属性就得使用绝对时间,比如当前时间就表示 为:System.currentTimeMillis()。

long intervalTime:
对于(2),(3),(4)方法来说,存在本属性,表示两次闹钟执行的间隔时间,也是以毫秒为单位。

PendingIntent pi:

需要一个pendingIntent对象,一般有三种形势,activity,broadcastReceiver,service

启动一个service:

    public static void setAlarmServiceTime(Context context, long timeInMillis, int time) {
        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, LocationService.class);
        PendingIntent sender = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        int interval = time;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            Log.v("wsh", "api大于19");
            //参数2是开始时间、参数3是允许系统延迟的时间
            am.setWindow(AlarmManager.RTC_WAKEUP, timeInMillis, interval, sender);
        } else {
            Log.v("wsh", "api小于19");
            am.setRepeating(AlarmManager.RTC_WAKEUP, timeInMillis, interval,sender;
}
   }

调用:AlarmUtils.setAlarmServiceTime(this, SystemClock.elapsedRealtime(), 5 * 1000);), 5 * 1000);

在service中为了防止API>19不周期性执行,所以重新调用:

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //因为setWindow只执行一次,所以要重新定义闹钟实现循环。
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            Log.v("wsh", "onStartCommand KITKAT " + flags);
            AlarmUtils.setAlarmServiceTime(this, SystemClock.elapsedRealtime(), 3 * 1000);
        }

        Log.v("wsh", "onStartCommand" + flags);
        return Service.START_STICKY;
    }

启动一个broadcastReceiver:

    public static void setAlarmReceiverTime(Context context, long timeInMillis, int time) {
        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

        PendingReceiver pendingReceiver = new PendingReceiver();

        IntentFilter filter = new IntentFilter();
        filter.addAction("com.pending");
        context.registerReceiver(pendingReceiver,filter);

        Intent intent = new Intent();
        intent.setAction("com.pending");
        intent.putExtra("pending","我是setAlarmReceiverTime");
        PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        int interval = time;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            Log.v("wsh", "api大于19");
            //参数2是开始时间、参数3是允许系统延迟的时间
            am.setWindow(AlarmManager.RTC_WAKEUP, timeInMillis, interval, sender);
        } else {
            Log.v("wsh", "api小于19");
            am.setRepeating(AlarmManager.RTC_WAKEUP, timeInMillis, interval, sender);
    }

调用:AlarmUtils.setAlarmReceiverTime(this, SystemClock.elapsedRealtime(), 3 * 1000);
在API>19时,设置的周期time不管用,默认每5s执行一次,不知道是什么原因。

你可能感兴趣的:(anroid笔记)