在Android Oreo及更高版本中的确切时间安排任务

问题描述 投票:1回答:3

有什么方法可以在Android(奥利奥和更高版本)上安排任务?我想安排位置跟踪开始/停止事件。假设每天9:00 AM开始位置跟踪,每天6:00 PM停止。请提出解决方案。警报管理器可以帮助我吗?

android location scheduled-tasks alarmmanager
3个回答
0
投票

如果应该是9 AM/6PM急AlarmManager是您的朋友,因为它可以在确切时间https://developer.android.com/reference/android/app/AlarmManager.html#setExactAndAllowWhileIdle(int,%20long,%20android.app.PendingIntent)触发警报。

[随着Doze模式的引入,JobSchedulerWorkManager上的权限级别更改可能会延迟15分钟,但它更灵活,并且计划的作业将通过系统重新启动而保持。

返回到Android优化,您应该考虑到事实,您不再可以使用后台服务进行定位,并且在实施该服务时,请注意获取它的方式,因为它可能会很快耗尽电池电量。

参考:https://developer.android.com/about/versions/oreo/background-location-limits

希望有帮助!


0
投票

有什么办法可以在Android(Oreo及以上版本)上安排任务?

是的,有解决方案。例如,您可以直接使用AlarmManagerEvernote Android Job(请阅读更多here)。不幸的是,Evernote Android Job已被弃用,并且不会发布任何新版本。但是,它非常简单易用,可以完美地实现您的目标。

简介

我注意到建议使用JobSchedulerWorkManager-是错误的。它们的设计方式使得它们可以合并来自多个应用程序的许多作业,因此它们并不具有确切的时间安排。

现在返回Evernote Android Job。使用它,您可以设置执行作业的确切时间,因为它在内部使用了AlarmManager

我将提供一个示例,说明如何通过Evernote作业以及AlarmManager实现所需的目标。但是,我将从第一个开始,因为我非常喜欢它的用法简单性:)。

Evernote示例

因此,我从Evernote页中获取了一个示例,并对其进行了一些修改以适合您的情况。

首先创建LocationTrackingJob,然后根据当天的时间启用/禁用位置跟踪。我只考虑几个小时,但是如果时间必须更精确,您可以自己轻松地改善它。

完成后,计算下一次作业执行之前必须经过的毫秒数,然后再次安排作业。请注意,它不能是定期工作:

LocationTrackingJob.java

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 
    } 
}

然后,您应该创建一个负责创建您的工作的类。

LocationTrackingJobCreator.java

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,以便应用程序启动后就可以启动作业。

App.java

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        // register your job creator here 
        JobManager.create(this).addJobCreator(new LocationTrackingJobCreator());
    }
}

我将由您决定是否进一步改进代码,但现在应该清楚如何实现和运行该作业。

AlarmManager示例

在这里,我们创建一个BroadcastReceiver,它负责接收定时事件并启用/禁用位置跟踪。略有不同是,我们提供了以毫秒为单位的确切时间,而不是必须发送事件的毫秒数。

LocationTrackingBroadcastReceiver.java

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()来启动位置跟踪:

App.java

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        // initiate tracking here
        LocationTrackingBroadcastReceiver.scheduleLocationTrackingEvent(this);
    }
}

结论

如果要在准确的时间运行作业,则JobSchedulerWorkManager不是正确的建议。相反,您应该使用AlarmManagerEvernote Android Job(因为它也很简单)。但是,后者已不再维护,将来可能会“遗忘”。


0
投票

有类似的问题。对我而言,最好的解决方案是实施Firebase Messaging,并将数据通知发送到设备,然后在onMessageReceived(RemoteMessage remoteMessage)中触发某些操作(例如,获取位置并将其发送到服务器)。要将其计划为从9:00 AM到06:00 PM,我将使用cron作业,该作业会触发firebase中的消息。奖励功能-您可以远程更改/暂停/开始更新(无需更新应用)。

© www.soinside.com 2019 - 2024. All rights reserved.