Android AlarmManager 定时任务/报警管理

Android AlarmManager  定时任务/报警管理

 

官方解释:AlarmManager类提供对系统警报服务的访问。这些允许您安排应用程序在将来的某个时间运行。当警报响起时,Intent系统会广播为其注册的警报,如果目标应用程序尚未运行,则会自动启动它。设备处于休眠状态时会保留已注册的警报(如果设备在此期间关闭,则可以选择将设备唤醒),但如果设备关闭并重新启动,则会清除AlarmManager的任务。

 

通俗一点AlarmManager 系统提供的一个定时任务管理器,通过AlarmManager 提供的定时任务,可以在约定的时间发送广播,启动服务,启动Activity等等。AlarmManager是Android中常用的一种系统级别的提示服务,在特定的时刻为我们广播⼀个指定的Intent。简单的说就是我们设定⼀一个时间,然后在该时间到来时,AlarmManager为 我们广播一个我们设定的Intent广播因此我们需要实现⼀一个针对特定闹钟事件的⼴播接⼝器 (PendingIntent)。

 

特点:使用它既可以指定单次执行的定时任务,也可以指定重复运行的周期性任务;

注意:从API 19开始,AlarmManager的机制都是非准确传递,操作系统将会转换闹钟,来最小化唤醒和电池使用,所以时间可能没那么精确;AlarmManager非常适合Android中定时任务.并且因为他具有唤醒CPU的功能,可以保证每次需要执行特定任务时CPU都能正常工作, 或者说当CPU处于休眠时注册的闹钟会被保留(可以唤醒CPU),(老司机们请注意此处有弯道减速慢行)但是国内Rom众多.有的可能休眠时候无法唤醒。

 

简单的使用流程

eg1:

  
int time = 60 * 1000 * 30;//30分钟
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, RepetitionService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT < 19) {
      alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + time, pendingIntent);
} else {
     alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + time, pendingIntent);
}

这里time 表示30分钟后, 会启动intent对象设置的RepetitionService 

下面看下RepetitionService 代码:

public class RepetitionService extends IntentService {


    public static final String TAG = "RepetitionService";


    public RepetitionService() {
        super("RepetitionService");
    }


    @Override
    public void onCreate() {
        super.onCreate();

        Log.d(TAG, "onCreate");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        做一些逻辑,由于IntentService 会进行异步处理, 
        所以这里可以直接写耗时逻辑,不会占用主线程耗时,不需要再开启异步线程,
        onHandleIntent 执行完后, Service会自动销毁;
    }


    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy");
        super.onDestroy();
    }
}

当然这里启动的是一个Service ,可以换为通过Intent发送一自定义Action的广播,用法类似;

通常要使用 PendingIntent,PendingIntent可以理解为Intent的封装包,简单的说就是在Intent上在加个指定的动作。在使用Intent的时候,我们还需要在执行startActivity、startService或sendBroadcast才能使Intent有用。而PendingIntent的话就是将这个动作包含在内了。

 

 

eg2:   设定指定时间后执行任务(用Calendar来定义时间)

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR,2016);
        calendar.set(Calendar.MONTH,Calendar.DECEMBER);
        calendar.set(Calendar.DAY_OF_MONTH,16);
        calendar.set(Calendar.HOUR_OF_DAY,11);
        calendar.set(Calendar.MINUTE,50);
        calendar.set(Calendar.SECOND,0);
        //设定时间为 2016年12月16日11点50分0秒

        AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

        Intent intent = new Intent(this, AlarmService.class);
        intent.setAction(AlarmService.ACTION_ALARM);
        PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        if(Build.VERSION.SDK_INT < 19){
            am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
        }else{
            am.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
        }
public class AlarmService extends Service {

    public static String ACTION_ALARM = "action_alarm";
    private Handler mHanler = new Handler(Looper.getMainLooper());

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mHanler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(AlarmService.this, "闹钟来啦", Toast.LENGTH_SHORT).show();
            }
        });
        return super.onStartCommand(intent, flags, startId);
    }
}

AlarmManager的几个方法:

 设置一次性闹钟:  

           set(int type, long triggerAtMillis, PendingIntent operation)

          第一个参数表示闹钟类型
          第二个参数表示闹钟执行时间
          第三个参数表示闹钟响应动作

设置重复闹钟: SDK_19 Android4.4 之前是精确闹钟,19以后为了节约电量,减少系统唤醒和电池的使用,所以时间没有那么精确了,但是不会差太多

          setRepeating(int type, long triggerAtMillis,long intervalMillis, PendingIntent operation)

          setInexactRepeating(int type, long triggerAtMillis,long intervalMillis, PendingIntent operation)

          第一个参数表示闹钟类型,
          第二个参数表示闹钟首次执行时间,
          第三个参数表示闹钟两次执行的间隔时间,
          第四个参数表示闹钟响应动作

设置精确闹钟:

          setExact(int type, long triggerAtMillis, PendingIntent operation)

          setWindow(int type, long windowStartMillis, long windowLengthMillis,PendingIntent operation)

取消闹钟:

         cancel(PendingIntent operation)

         取消Intent相同的闹钟,这里是根据Intent中filterEquals(Intent other)方法来判断是否相同,

public boolean filterEquals(Intent other) {
        if (other == null) {
            return false;
        }
        if (!Objects.equals(this.mAction, other.mAction)) return false;
        if (!Objects.equals(this.mData, other.mData)) return false;
        if (!Objects.equals(this.mType, other.mType)) return false;
        if (!Objects.equals(this.mPackage, other.mPackage)) return false;
        if (!Objects.equals(this.mComponent, other.mComponent)) return false;
        if (!Objects.equals(this.mCategories, other.mCategories)) return false;

        return true;
}

可以看到,从方法体可以看出mAction、mData、mType、mPackage、mComponent、mCategories这几个完全一样就认定为同一Intent ,才能取消, 否则认为不是同一个Intent ,就不能取消,时间到了之后还是会执行;

 

闹钟类型

  • AlarmManager.ELAPSED_REALTIME
    • 在指定的延时过后,发送广播,但不唤醒设备(闹钟在睡眠状态下不可用)。如果在系统休眠时闹钟触发,它将不会被传递,直到下一次设备唤醒。设备休眠时并不会唤醒设备;
  • AlarmManager.ELAPSED_REALTIME_WAKEUP
    • 在指定的延时过后,发送广播,并唤醒设备(即使关机也会执行operation所对应的组件)。与ELAPSED_REALTIME基本功能一样,只是会在设备休眠时唤醒设备;
  • AlarmManager.RTC
    • 使用绝对时间,可以通过 System.currentTimeMillis()获取,设备休眠时并不会唤醒设备;
  • AlarmManager.RTC_WAKEUP
    • 与RTC基本功能一样,只是会在设备休眠时唤醒设备

 

闹钟重复类型

  • AlarmManager.INTERVAL_FIFTEEN_MINUTES 间隔15分钟
  • AlarmManager.INTERVAL_HALF_HOUR 间隔半个小时
  • AlarmManager.INTERVAL_HOUR 间隔一个小时
  • AlarmManager.INTERVAL_HALF_DAY 间隔半天
  • AlarmManager.INTERVAL_DAY 间隔一天

 

设定多个定时闹钟为什么只有最后一个生效

AlarmManager 根据 PendingIntent requestCode 来判断是否是同一个定时服务,所以当requestCode相等的时候只有最后一个生效

1. 我们说的requestCode 是第二个参数

PendingIntent.getBroadcast(Context context, int requestCode, Intent intent, @Flags int flags)

2. 例如:

PendingIntent pi1 = PendingIntent.getBroadcast(this, 1, intent, 0); 
AlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, startTime, intervalTime, pi1);  

PendingIntent pi2 = PendingIntent.getBroadcast(this, 2, intent, 0); 
AlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, startTime, intervalTime, pi2); 

这个样子就可以设定2个了

 

 

 

 

 

 

 

 

你可能感兴趣的:(android,技巧)