一:AlarmManager
- AlarmManager允许您设置自己的应用在将来的某个时间运行。当定时时间到时,系统会发出应用注册的Intent,如果目标应用程序尚未运行,则会自动启动它。设备处于休眠状态时会保留已设置的alarm,如果设备在此期间休眠则可以选择将设备唤醒,但如果设备重启则会清除AlarmManager的任务。
使用方法:
- 初始化PendingIntent
Intent intent = new Intent(this, AlarmService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
2. 初始化AlarmManager
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
3. 设置定时任务
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), TIME_INTERVAL, pendingIntent);
常用方法:
API 19之前常用方法:
set(int type,long startTime,PendingIntent pi)//该方法用于设置一次性定时器。
setRepeating(int type,long startTime,long intervalTime,PendingIntent pi)//该方法用于设置
可重复执行的定时器。
setInexactRepeating(int type,long startTime,long intervalTime,PendingIntent pi)//该方法用于设置可重复执行的定时器。与setRepeating相比,这个方法更加考虑系统电量,比如系统在低电量情况下可能不会严格按照设定的间隔时间执行闹钟,因为系统可以调整报警的交付时间,使其同时触发,避免超过必要的唤醒设备。
Demo:定时跳转服务开启通知
@SuppressLint("ShortAlarm") private void initAlarmManager() {
final long TIME_INTERVAL = 6 * 1000;//闹钟执行任务的时间间隔
Intent intent = new Intent(this, AlarmService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), TIME_INTERVAL, pendingIntent);
}@Override public int onStartCommand(Intent intent, int flags, int startId) {
NotificationManager manager = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(FIRST_CHANNEL, "ServiceChannel", NotificationManager.IMPORTANCE_DEFAULT);
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);
Log.d(TAG, "onStartJob chananel...............");
}
Intent notifyIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifyIntent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setChannelId(FIRST_CHANNEL)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.apple))
.setContentTitle(getString(R.string.notify_title))
.setContentText(getString(R.string.notify_text))
.setPriority(Notification.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setShowWhen(true)
.build();
if (manager != null) {
manager.notify(1, notification);
}
return START_STICKY;
}
二:JobScheduler
特性:条件式触发,把不紧急的工作留待条件更充分的时候完成。
(1)JobScheduler允许开发者创建在后台执行的job,当预置的条件被满足时,这些Job将会在后台被执行。
(2)若你不指定作业运行截止时间的话,这个作业会由JobSchedule内部队列决定在哪一个时刻运行。简单的来说就是它既可以在某一段时间后执行,又可以在某一个特殊场景下执行,比如充电、网络状态、设备空闲。这样来看线程池或者AlarmManager就不满足上述的需求了,JobSchedule既满足多任务执行的功能,同时也可以降低电池电量的消耗。
(3)JobScheduler Api可以在我们的App中执行一些操作,这些操作将会在我们预置的一些条件被满足的时候被执行。和AlarmManager不一样,执行这些操作的时间并不是严格准确的。 JobScheduler会把一系列的job收集起来一起执行,这样既允许我们的job被执行,又能兼顾到手机电量的使用情况,达到节电的目的。
使用方法
- JobScheduler : 任务调度器,系统提供的任务调度服务,它的实例从系统服务Context.JOB_SCHEDULER_SERVICE中获得
- JobInfo : 任务概要信息,描述任务的执行时间,条件,策略等一系列的行为
- JobService : 任务服务,它描述了该任务内部的具体业务逻辑,它的运行时刻由JobScheduler根据JobInfo指定的条件而计算决定。
- Jobscheduler的使用流程大概分为以下四个部分:
- 派生JobService 子类,定义需要执行的任务(UI线程)
- 从Context 中获取JobScheduler 实例(相当于管理器)
- 构建JobInfo 实例,指定 JobService任务实现类及其执行条件
- 通过JobScheduler 实例加入到任务队列
private void initSchJob() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
Log.d(TAG, "initSchJob..........");
JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo.Builder builder = new JobInfo.Builder(mJobId ++,
new ComponentName(getPackageName(), JobSchedService.class.getName()));
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
int schedule = jobScheduler.schedule(builder.build());
Log.d(TAG, "initSchJob, schedule: " + schedule);
}
}public class JobSchedService extends JobService { private static final String TAG = "JobSchedService";
private final String FIRST_CHANNEL = "job channel";
public JobSchedService() {
}
@Override
public boolean onStartJob(JobParameters params) {
Log.d(TAG, "onStartJob.........");
NotificationManager manager = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(FIRST_CHANNEL, "ServiceChannel", NotificationManager.IMPORTANCE_DEFAULT);
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);
Log.d(TAG, "onStartJob chananel...............");
}
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("notify", "PopDialog");
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setChannelId(FIRST_CHANNEL)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.apple))
.setContentTitle(getString(R.string.notify_title))
.setContentText(getString(R.string.notify_text))
.setPriority(Notification.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setShowWhen(true)
.build();
if (manager != null) {
manager.notify(1, notification);
}
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
return true;
}
}
- JobScheduler使用要注意的坑
- 当做完自己的任务要及时调用JobFinished 来结束自己的任务:耗电
- 兼容性问题:只有Android L及以上的设备才支持
- JobService可能运行在主线程,注意ANR
- cancelAll会取消该uid下的所有jobs,也就是说当存在多个app通过shareUid的方式,那么在其中任意一个app执行cancelAll(),则会把所有同一uid下的app中的jobs都cancel掉。
- 同一个包名下,有两个相同的jobId时 ,此时只能有一个job生效,另一个无效。
总结:
- AlarmManager利用系统层级的闹钟服务(持有WakeLock),可以指定时间执行任务:
- 需要精确的定时任务,如闹钟。
- 非精准定时任务,可以推迟任务使多个任务同时执行而避免频繁唤醒系统
- 网络请求相关的业务不使用AlarmManager
- Job Scheduler作为系统服务运行在系统层面,可以指定运行条件(充电状态、Wifi状态、设备空闲),将收到的任务在合适的时间、状态一起执行。
- 网络请求相关业务放到Job Scheduler执行
- 一些与特定场景(JobInfo)绑定的任务
- 非精确性的定时任务建议使用Job来代替Alarm,能更加准确的满足条件的执行你想要执行的任务;网络相关定时任务禁止使用AlarmManager。
- 需要执行相对精确性的定时任务,而必须使用Alarm时,建议使用非精准Alarm。一般情况下禁止设置精准Alarm,闹钟类应用除外。