Android闹钟设置不像IOS那么简单。做过Android闹钟设置的开发者都知道这个坑有多深。下面记录下我对安卓闹钟设置的解决方法。主要问题API19开始修改AlarmManager的机制。应用程序被杀死后,设置的闹钟将不会响起。在6.0以上进入Doze模式将使JobScheduler停止工作。重启手机设置后,闹钟失效。API19以上AlarmManager机制修改在API19之前,AlarmManager提供了三种设置闹钟的方法。由于业务需求闹钟只需要使用一次,set(inttype,longstartTime,PendingIntentpi);使用此方法。从API19开始,AlarmManager的机制是非精确传递,操作系统会切换闹钟以最小化唤醒和电池使用。由于之前的程序没有处理API19以上的闹钟设置,导致4.4以上手机的闹钟设置没有反应(不杀应用是没有闹钟的)。所以设置闹钟需要根据API版本单独处理。代码如下:recordTime,TimeUtils.NO_SECOND_FORMAT),sender);}else{am.set(AlarmManager.RTC_WAKEUP,TimeUtils.stringToLong(recordTime,TimeUtils.NO_SECOND_FORMAT),sender);}这样可以保证闹钟在应用程序启动时闹钟没有被杀死。应用被杀时的处理应用被杀后,设置的闹钟失效。这里使用daemon进程和graykeep-alive来保证后台闹钟服务不会被kill掉。当应用程序和闹钟服务被杀死后,守护进程和灰度保活会重启闹钟服务,重新设置闹钟。关于daemon进程的处理,这里使用了一个开源的daemon进程库。Android-AppDaemon在闹钟服务的onCreat中加入Android-AppDaemon的开源守护进程。代码如下:@OverridepublicvoidonCreate(){super.onCreate();Daemon.run(DaemonService.this,DaemonService.class,Daemon.INTERVAL_ONE_MINUTE);startTimeTask();grayGuard();}以进一步保证存活闹钟服务,添加Keepitgrayed(利用系统漏洞启动前台Service)。代码如下:privatevoidgrayGuard(){if(Build.VERSION.SDK_INT<18){//API<18,该方法可以有效隐藏Notification上的图标startForeground(GRAY_SERVICE_ID,newNotification());}else{IntentinnerIntent=newIntent(this,DaemonInnerService.class);startService(innerIntent);startForeground(GRAY_SERVICE_ID,newNotification());}//发送唤醒广播提示挂起的UI进程重启AlarmManageralarmManager=(AlarmManager)getSystemService(Context.ALARM_SERVICE);IntentalarmIntent=newIntent();alarmIntent.setAction(WakeReceiver.GRAY_WAKE_ACTION);PendingIntentoperation=PendingIntent.getBroadcast(这,WAKE_REQUEST_CODE,alarmIntent,PendingIntent.FLAG_UPDATE_CURRENT);if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.KindMankAT){WalarmAlarmManager.RTC_WAKEUP,System.currentTimeMillis(),ALARM_INTERVAL,operation);}else{alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),ALARM_INTERVAL,operation);}}/***对于有API的平台>=18灰色keep-a上面使用的live方法*/publicstaticclassDaemonInnerServiceextendsService{@OverridepublicvoidonCreate(){Log.i(LOG_TAG,"InnerService->onCreate");super.onCreate();}@OverridepublicintonStartCommand(Intentintent,intflags,intstartId){Log.i(LOG_TAG,"InnerService->onStartCommand");startForeground(GRAY_SERVICE_ID,newNotification());//stopForeground(true);stopSelf();returnsuper.onStartCommand(intent,flags,startId);}@OverridepublicIBinderonBind(Intentintent){thrownewUnsupportedOperationException("Notyeimplemented");}@OverridepublicvoidonDestroy(日志。i(LOG_TAG,"InnerService->onDestroy");super.onDestroy();}}以上操作可以尽可能的提高闹钟服务的存活率,闹钟服务会被彻底杀死。为了解决5.0以上的问题,这里介绍一下5.0以上的新特性JobScheduler,对于5.0以上的JobScheduler,可以先阅读这篇关于5.0中新的JobSchedulerAPI的文章,这里使用5.0以上的JobScheduler创建一个定时任务,定时检查是否闹钟服务存在,重启闹钟服务(如果不存在)。(这里我设置的闹钟服务每分钟检测一次)进入应用时,检查当前系统是否在5.0以上,如果是,则启动JobScheduler服务。代码如下:JobSchedulerService.class.getName()));builder.setPeriodic(60*1000);//每60秒运行一次builder.setRequiresCharging(true);builder.setPersisted(true);//设置是否重新执行任务生成器重启设备后.setRequiresDeviceIdle(true);if(mJobScheduler.schedule(builder.build())<=0){//Ifsomethinggoeswrong}}builder.setPersisted(true);method是设备重启后是否重新执行任务,这里测试是可以重启任务的。以上操作进一步保证了闹钟服务被杀掉后重启。不过6.0以上引入了Doze模式。6.0以上的手机进入该模式后,JobScheduler会停止工作。6.0以上Doze模式的处理为了让JobScheduler能够在6.0以上的Doze模式下工作,这里针对6.0以上的Doze模式做了特殊处理——忽略电池优化。在Manifest.xml中添加权限。
