即使手机在睡觉,服务仍在运行?

我在我的应用程序中有一个服务,每10分钟运行一次。 它基本上检查我们的服务器,看看是否一切正常运行,并通知用户任何问题。 我创build了这个应用程序供我们公司内部使用。

我的同事在长周末使用了应用程序,并注意到设备进入睡眠状态时没有执行任何检查。 我的印象是,服务应该继续在后台运行,直到我明确地调用我的代码中的stopService()

因此,最终,我的目标是让服务运行,直到用户点击应用程序中的closuresbutton或终止进程。

我听说WakeLock是为了防止屏幕closures,这不是我想要的。 然后我听说另外一个称为部分WakeLock的东西,即使在设备睡着的时候也能保持CPU运行。 后者听起来更接近我所需要的。

我如何获得这个WakeLock,我应该什么时候发布它,还有其他方法呢?

注意:这篇文章已经更新,包括Android Lollipop版本的JobScheduler API。 以下方法仍然是一种可行的方法,但如果您的目标是Android棒棒糖或更高版本,则可以考虑弃用。 请参阅下半部分的JobSchedulerselect。

一个做经常性任务的方法是这样的:

  • 创build一个类AlarmReceiver

     public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent myService = new Intent(context, YourService.class); context.startService(myService); } } 

    YourService是您的服务;-)

如果您的任务需要唤醒锁,build议从WakefulBroadcastReceiver扩展。 在这种情况下,不要忘记在你的Manifest中添加WAKE_LOCK权限!

  • 创build一个待定的意图

要开始经常性轮询,请在您的活动中执行以下代码:

 Intent myAlarm = new Intent(getApplicationContext(), AlarmReceiver.class); //myAlarm.putExtra("project_id", project_id); //Put Extra if needed PendingIntent recurringAlarm = PendingIntent.getBroadcast(getApplicationContext(), 0, myAlarm, PendingIntent.FLAG_CANCEL_CURRENT); AlarmManager alarms = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE); Calendar updateTime = Calendar.getInstance(); //updateTime.setWhatever(0); //set time to start first occurence of alarm alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), AlarmManager.INTERVAL_DAY, recurringAlarm); //you can modify the interval of course 

这段代码设置了一个alarm和一个可取消的pendingIntent。 alarmManager每天(第三个参数)获取作业重复recurringAlarm alarmManager ,但不精确,所以CPU在间隔后大致醒来,但并不准确(让操作系统select最佳时间,从而减less电池消耗)。 第一次警报(和服务)开始将是您selectupdateTime的时间。

  • 最后但并非最不重要的是:这里是如何杀死经常发生的警报

     Intent myAlarm = new Intent(getApplicationContext(), AlarmReceiver.class); //myAlarm.putExtra("project_id",project_id); //put the SAME extras PendingIntent recurringAlarm = PendingIntent.getBroadcast(getApplicationContext(), 0, myAlarm, PendingIntent.FLAG_CANCEL_CURRENT); AlarmManager alarms = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE); alarms.cancel(recurringAlarm); 

此代码会创build(可能)现有警报的副本,并通知警报pipe理器取消所有此类警报。

  • Manifest中当然也有一些事情要做:

包括这两行

  < receiver android:name=".AlarmReceiver"></receiver> < service android:name=".YourService"></service> 

< application> -tag里面。 没有它,系统不接受服务的周期性警报的开始。


Android Lollipop版本开始,有一个优雅地解决这个任务的新方法。 这也使得只有在networking状态等特定标准得到满足的情况下才能执行一个动作。

 // wrap your stuff in a componentName ComponentName mServiceComponent = new ComponentName(context, MyJobService.class); // set up conditions for the job JobInfo task = JobInfo.Builder(mJobId, mServiceComponent) .setPeriodic(mIntervalMillis) .setRequiresCharging(true) // default is "false" .setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED) // Parameter may be "ANY", "NONE" (=default) or "UNMETERED" .build(); // inform the system of the job JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); jobScheduler.schedule(task); 

您也可以使用setOverrideDeadline(maxExecutionDelayMillis)提供最后期限。

为了摆脱这样的任务,只需调用jobScheduler.cancel(mJobId);jobScheduler.cancelAll();

我会build议,如果从一开始就构build这个应用程序来使用服务器端组件(是的,也需要监视!)并且发送推送通知,那么轮询从来就不是可靠的解决scheme。