定时任务
常用的定时任务有Timer, Handler, AlarmManager
Timer
有一个明显的问题,就是它并不适合用于需要长期在后台运行的定时任务。
手机为了能让电池更加耐用,会采用自己的休眠策略而让CPU进入睡眠状态,极有可能导致Timer中的定时任务停止或者无法正常运行。
Handler
Handler的postDelay方法存在同样的问题,因为默认Handler依赖于线程,所以,只要进程被杀死,相关的定时操作也就无效了。
AlarmManager
它通过pendingIntent具有唤醒未启动进程的功能,即可以保证每次需要执行的定时任务的时候CPU都能正常工作。
注意当设备关机或者重启后,闹钟会被清除。
AlarmManager
实例——音乐定时关闭
初使化两个变量,方便在onDestroy时进行注销
private PendingIntent mPendingIntent;
private AlarmManager mAlarmManager;
实例化变量并设置定时任务
通过发送广播来执行定时事件
//注册广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.zqunyan.zgexplorer.musicplay.close");
registerReceiver(mBroadcabast, intentFilter);
mPendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_NO_CREATE);
mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
//点击启动事件
mView.grpTimeClose.setOnCheckedChangeListener((radioGroup, i) -> {
if(mPendingIntent != null) mAlarmManager.cancel(mPendingIntent);
//if (mTimer != null) mTimer.cancel();
int delay = 15000;
// mTimer = new Timer();
// mTimer.schedule(new TimerTask() {
// @Override
// public void run() {
// rTimer.cancel();
// MusicPlayActivity.this.finish();
// System.exit(0);
// }
// }, delay);
//AlarmManager
mPendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mAlarmManager.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + delay, mPendingIntent);
}
});
private final BroadcastReceiver mBroadcabast = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
System.exit(0);
}
};
@Override
protected void onDestroy() {
if(mPendingIntent != null) mAlarmManager.cancel(mPendingIntent);
//取消注册的广播
unregisterReceiver(mBroadcabast);
super.onDestroy();
}
常用方法
setAndAllowWhileIdle
如果想让闹钟在手机休眠时依然能够执行,则要使用 setAndAllowWhileIdle 和 setExactAndAllowWhileIdle 。
第一个参数为闹钟类型,一般为 AlarmManager.ELAPSED_REALTIME_WAKEUP 或者 AlarmManager.RTC_WAKEUP 。区别就是前者是从手机开机后的时间,包含了手机睡眠时间;而后者使用的就是手机系统设置中的时间
第二个参数表示任务首次执行时间:与第一个参数密切相关。第一个参数若为 AlarmManager.ELAPSED_REALTIME_WAKEUP
,那么当前时间就为 SystemClock.elapsedRealtime()
;若为 AlarmManager.RTC_WAKEUP
,那么当前时间就为 System.currentTimeMillis()
第三个参数表示对应的响应动作:一般都是去发送广播,然后在广播接收 onReceive(Context context, Intent intent)
中做相关操作
PendingIntent
Intent更加倾向于立即执行某个动作,而PendingIntent更加倾向于在某个合适的时机去执行某个动作,所以,可以把PendingIntent简单地理解为延迟执行的Intent.
FLAG
传入0表示不打算使用任何一种FLAG
-
FLAG_CANCEL_CURRENT
如果要创建的PendingIntent已经存在了,那么在创建新的PendingIntent之前,原先已经存在的PendingIntent中的intent将不能使用
-
FLAG_NO_CREATE
如果要创建的PendingIntent尚未存在,则不创建新的PendingIntent,直接返回null
-
FLAG_ONE_SHOT
相同的PendingIntent只能使用一次,且遇到相同的PendingIntent时不会去更新PendingIntent中封装的Intent的extra部分的内容
-
FLAG_UPDATE_CURRENT
如果要创建的PendingIntent已经存在了,那么在保留原先PendingIntent的同时,将原先PendingIntent封装的Intent中的extra部分替换为现在新创建的PendingIntent的intent中extra的内容
判断PendingIntent是否存在
public static boolean isPendingIntentAvailable(Context context) {
Intent intent = new Intent();
intent.setAction("com.zqunyan.zgexplorer.musicplay.close");
PendingIntent mPendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_NO_CREATE);
return mPendingIntent != null;
}
if(mPendingIntent != null) mAlarmManager.cancel(mPendingIntent);