有什么方法可以在Android(奥利奥和更高版本)上安排任务?我想安排位置跟踪开始/停止事件。假设每天9:00 AM开始位置跟踪,每天6:00 PM停止。请提出解决方案。警报管理器可以帮助我吗?
如果应该是9 AM/6PM急AlarmManager
是您的朋友,因为它可以在确切时间https://developer.android.com/reference/android/app/AlarmManager.html#setExactAndAllowWhileIdle(int,%20long,%20android.app.PendingIntent)触发警报。
[随着Doze
模式的引入,JobScheduler
和WorkManager
上的权限级别更改可能会延迟15分钟,但它更灵活,并且计划的作业将通过系统重新启动而保持。
返回到Android优化,您应该考虑到事实,您不再可以使用后台服务进行定位,并且在实施该服务时,请注意获取它的方式,因为它可能会很快耗尽电池电量。
参考:https://developer.android.com/about/versions/oreo/background-location-limits
希望有帮助!
有什么办法可以在Android(Oreo及以上版本)上安排任务?
是的,有解决方案。例如,您可以直接使用AlarmManager
或Evernote Android Job
(请阅读更多here)。不幸的是,Evernote Android Job
已被弃用,并且不会发布任何新版本。但是,它非常简单易用,可以完美地实现您的目标。
我注意到建议使用JobScheduler
或WorkManager
-是错误的。它们的设计方式使得它们可以合并来自多个应用程序的许多作业,因此它们并不具有确切的时间安排。
现在返回Evernote Android Job
。使用它,您可以设置执行作业的确切时间,因为它在内部使用了AlarmManager
。
我将提供一个示例,说明如何通过Evernote
作业以及AlarmManager
实现所需的目标。但是,我将从第一个开始,因为我非常喜欢它的用法简单性:)。
因此,我从Evernote页中获取了一个示例,并对其进行了一些修改以适合您的情况。
首先创建LocationTrackingJob
,然后根据当天的时间启用/禁用位置跟踪。我只考虑几个小时,但是如果时间必须更精确,您可以自己轻松地改善它。
完成后,计算下一次作业执行之前必须经过的毫秒数,然后再次安排作业。请注意,它不能是定期工作:
public class LocationTrackingJob extends Job {
public static final String TAG = "job_location_tracking_tag";
@Override
@NonNull
protected Result onRunJob(Params params) {
Calendar calendar = Calendar.getInstance();
int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY);
Calendar nextCalendar = (Calendar) calendar.clone();
if (hourOfDay >= 10 && hourOfDay < 18) {
startLocationTracking();
nextCalendar.set(Calendar.HOUR_OF_DAY, 18);
} else {
stopLocationTracking();
nextCalendar.add(Calendar.DATE, 1);
nextCalendar.set(Calendar.HOUR_OF_DAY, 10);
}
nextCalendar.set(Calendar.MINUTE, 0);
nextCalendar.set(Calendar.SECOND, 0);
// calculate in how many millis the job should be run again
long executionMillis = nextCalendar.getTimeInMillis() - calendar.getTimeInMillis();
scheduleLocationTrackingJob(executionMillis);
return Result.SUCCESS;
}
// this method will be used externally to start the job from the outside
public static void scheduleLocationTrackingJob() {
// initially start your job right away and it picks the proper action on its own
scheduleLocationTrackingJob(0);
}
private static void scheduleLocationTrackingJob(long executionMillis) {
new JobRequest.Builder(LocationTrackingJob.TAG)
.setExact(executionMillis)
.build()
.schedule();
}
private void startLocationTracking() {
// add your code here
}
private void stopLocationTracking() {
// add your code here
}
}
然后,您应该创建一个负责创建您的工作的类。
public class LocationTrackingJobCreator implements JobCreator {
@Override
@Nullable
public Job create(@NonNull String tag) {
switch (tag) {
case LocationTrackingJob.TAG:
return new LocationTrackingJob();
default:
return null;
}
}
}
最后,在应用程序的班级中注册LocationTrackingJobCreator
,以便应用程序启动后就可以启动作业。
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
// register your job creator here
JobManager.create(this).addJobCreator(new LocationTrackingJobCreator());
}
}
我将由您决定是否进一步改进代码,但现在应该清楚如何实现和运行该作业。
在这里,我们创建一个BroadcastReceiver
,它负责接收定时事件并启用/禁用位置跟踪。略有不同是,我们提供了以毫秒为单位的确切时间,而不是必须发送事件的毫秒数。
public class LocationTrackingBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
Calendar calendar = Calendar.getInstance();
int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY);
Calendar nextCalendar = (Calendar) calendar.clone();
if (hourOfDay >= 10 && hourOfDay < 18) {
startLocationTracking();
nextCalendar.set(Calendar.HOUR_OF_DAY, 18);
} else {
stopLocationTracking();
nextCalendar.add(Calendar.DATE, 1);
nextCalendar.set(Calendar.HOUR_OF_DAY, 10);
}
nextCalendar.set(Calendar.MINUTE, 0);
nextCalendar.set(Calendar.SECOND, 0);
scheduleLocationTrackingEvent(context, nextCalendar.getTimeInMillis());
}
public static void scheduleLocationTrackingEvent(Context context) {
scheduleLocationTrackingEvent(context, Calendar.getInstance().getTimeInMillis());
}
private static void scheduleLocationTrackingEvent(Context context, long executionMillis) {
Intent startIntent = new Intent(context, LocationTrackingBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, startIntent,PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
int ALARM_TYPE = AlarmManager.RTC_WAKEUP;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(ALARM_TYPE, executionMillis, pendingIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(ALARM_TYPE, executionMillis, pendingIntent);
} else {
alarmManager.set(ALARM_TYPE, executionMillis, pendingIntent);
}
}
private void startLocationTracking() {
// add your code here
}
private void stopLocationTracking() {
// add your code here
}
}
当然可以通过在应用程序的类中调用scheduleLocationTrackingEvent()
来启动位置跟踪:
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
// initiate tracking here
LocationTrackingBroadcastReceiver.scheduleLocationTrackingEvent(this);
}
}
如果要在准确的时间运行作业,则JobScheduler
或WorkManager
不是正确的建议。相反,您应该使用AlarmManager
或Evernote Android Job
(因为它也很简单)。但是,后者已不再维护,将来可能会“遗忘”。
有类似的问题。对我而言,最好的解决方案是实施Firebase Messaging,并将数据通知发送到设备,然后在onMessageReceived(RemoteMessage remoteMessage)
中触发某些操作(例如,获取位置并将其发送到服务器)。要将其计划为从9:00 AM到06:00 PM,我将使用cron作业,该作业会触发firebase中的消息。奖励功能-您可以远程更改/暂停/开始更新(无需更新应用)。