2016-01-31 7 views
1

Я пытаюсь создать простое приложение для аварийных сигналов, где будильник должен срабатывать в течение нескольких дней.Android: Служба сигнализации не работает

Я создал службу, которая регистрирует диспетчер аварийных сообщений на основе данных, сохраненных в настройках. Все работает нормально, за исключением того, что приложение не запускает будильник, когда приложение не работает.

AlarmService.java

@Override 
    protected void onHandleIntent(Intent intent) { 

     Toast.makeText(this,"Service started",Toast.LENGTH_LONG); 
     //set separate pending intent values for all days 
     setIntents(); 
     // register the alarm manager here 
     alarmManager = (AlarmManager)(getSystemService(Context.ALARM_SERVICE)); 
     execute(); 
    } 

    private void execute() { 

     prefs=getSharedPreferences("user_data_pref",Context.MODE_PRIVATE); 
     prefEditor=prefs.edit(); 

     int hour=prefs.getInt("ALARM_HOUR",0); 
     int minute=prefs.getInt("ALARM_MINUTE",0); 

     if(prefs.getString("ALARM_STATUS","NOT_SET").equals("SET")) 
      isAlarmOn=true; 
     if(prefs.getString("NOTIFICATION_STATUS","NOT_SET").equals("SET")) 
      isNotificationOn=true; 

     if (prefs.getBoolean("MON_SET",false)) { 
      setAlarmFor(Calendar.MONDAY,hour,minute,mondayIntent,isAlarmOn,isNotificationOn); 
     } 
     if (prefs.getBoolean("TUE_SET",false)) { 
      setAlarmFor(Calendar.TUESDAY,hour,minute,tuesdayIntent,isAlarmOn,isNotificationOn); 
     } 
     if (prefs.getBoolean("WED_SET",false)) { 
      setAlarmFor(Calendar.WEDNESDAY,hour,minute,wednesdayIntent,isAlarmOn,isNotificationOn); 
     } 
     if (prefs.getBoolean("THU_SET",false)) { 
      setAlarmFor(Calendar.THURSDAY,hour,minute,thursdayIntent,isAlarmOn,isNotificationOn); 
     } 
     if (prefs.getBoolean("FRI_SET",false)) { 
      setAlarmFor(Calendar.FRIDAY,hour,minute,fridayIntent,isAlarmOn,isNotificationOn); 
     } 
     if (prefs.getBoolean("SAT_SET",false)) { 
      setAlarmFor(Calendar.SATURDAY,hour,minute,saturdayIntent,isAlarmOn,isNotificationOn); 
     } 
     if (prefs.getBoolean("SUN_SET",false)) { 
      setAlarmFor(Calendar.SUNDAY,hour,minute,sundayIntent,isAlarmOn,isNotificationOn); 
     } 
} 
    private void setAlarmFor(int weekday, int hour, int minute, PendingIntent pendingIntent, boolean isAlarmOn, boolean isNotificationOn){ 
     if(isAlarmOn){ 
      prefEditor.putString("ALARM_STATUS","SET"); 
      prefEditor.commit(); 
     } 
     if(isNotificationOn){ 
      prefEditor.putString("NOTIFICATION_STATUS","SET"); 
      prefEditor.commit(); 
     } 

     Calendar calendar = Calendar.getInstance(); 
     calendar.set(Calendar.DAY_OF_WEEK,weekday); 
     calendar.set(Calendar.HOUR_OF_DAY, hour); 
     calendar.set(Calendar.MINUTE, minute); 
     calendar.set(Calendar.SECOND,0); 

     /* Repeating on every week interval */ 
     alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 
       7*24*60*60*1000, pendingIntent); 
    } 
    private void setIntents(){ 
     Intent intent = new Intent(this,AlarmReceiver.class); 
     mondayIntent=PendingIntent.getBroadcast(this, Calendar.MONDAY, intent, 0); 
     tuesdayIntent=PendingIntent.getBroadcast(this, Calendar.TUESDAY, intent, 0); 
     wednesdayIntent=PendingIntent.getBroadcast(this, Calendar.WEDNESDAY, intent, 0); 
     thursdayIntent=PendingIntent.getBroadcast(this, Calendar.THURSDAY, intent, 0); 
     fridayIntent=PendingIntent.getBroadcast(this, Calendar.FRIDAY, intent, 0); 
     saturdayIntent=PendingIntent.getBroadcast(this, Calendar.SATURDAY, intent, 0); 
     sundayIntent=PendingIntent.getBroadcast(this, Calendar.SUNDAY, intent, 0); 
    } 

Это должно вызвать AlarmReceiver класс, который отображает сигнал тревоги.

AlarmReceiver.java

@Override 
public void onReceive(Context context, Intent intent) { 
    prefs=context.getSharedPreferences("user_data_pref",Context.MODE_PRIVATE); 
    //Get Status of currently set alarm and notification 
    alarmStatus=prefs.getString("ALARM_STATUS","NOT_SET"); 
    notificationStatus=prefs.getString("NOTIFICATION_STATUS","NOT_SET"); 
    //Send notification if the notification is set 
    if(notificationStatus.equals("SET")){ 
     Toast.makeText(context, "NOTIFICATION START SUCCESSFUL", Toast.LENGTH_SHORT).show(); 
     playNotificationSound(context,getNotificationSound()); 
     NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context) 
       .setContentTitle("") // title for notification 
       .setContentText("") // message for notification 
       .setAutoCancel(true); // clear notification after click 
     Intent intent_1 = new Intent(context, MainActivity.class); 
     PendingIntent pi = PendingIntent.getActivity(context, 11, intent_1, Intent.FLAG_ACTIVITY_NEW_TASK); 
     mBuilder.setContentIntent(pi); 
     NotificationManager mNotificationManager = 
       (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 
     mNotificationManager.notify(0, mBuilder.build()); 
     displayNotification(context); 
    } 
    //Fire Alarm if the Alarm is set 
    if(alarmStatus.equals("SET")){ 
     Toast.makeText(context, "ALARM START SUCCESSFUL", Toast.LENGTH_SHORT).show(); 
     /** Creating Alarm */ 
     Intent i = new Intent(context,FitterfoxAlarmActivity.class); 
     i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
     context.startActivity(i); 
    } 
} 

AndroidManifest.xml

<receiver android:name=".OnBootReceiver"> 
     <intent-filter> 
      <action android:name="android.intent.action.BOOT_COMPLETED" /> 
     </intent-filter> 
    </receiver> 
    <receiver android:name=".AlarmReceiver"></receiver> 

    <service android:name=".AlarmService"></service> 
+0

Каков уровень API устройства или эмулятора, на котором вы тестируете? –

+0

Убедитесь, что 'AlarmReceiver' объявлен в манифесте. Если это не так, и только динамически регистрируется какой-либо деятельностью приложения, это объясняет, почему «AlarmReceiver» не срабатывает, когда приложение не запущено. –

+0

Я добавил код манифеста. Что-то не так в моих заявлениях? –

ответ

0

Попробуйте этот набор кода ваша служба никогда не собирается останавливаться, это работает для меня. «alarmManager.setRepeating» не работает во многих устройствах lollipop и marshmallows после его запуска, а затем потеряет контроль над сервисом, это поможет вам.

if (android.os.Build.VERSION.SDK_INT >= 23) { 
    piLR = PendingIntent.getBroadcast(context, 0, intentLR, 
      PendingIntent.FLAG_UPDATE_CURRENT); 
    amLR.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, 
      interval, piLR); 
} else if (android.os.Build.VERSION.SDK_INT >= 19 
     && android.os.Build.VERSION.SDK_INT < 23) { 
    piLR = PendingIntent.getBroadcast(context, 0, intentLR, 
      PendingIntent.FLAG_UPDATE_CURRENT); 
    amLR.setInexactRepeating(AlarmManager.RTC_WAKEUP, 
      System.currentTimeMillis(), interval, piLR); 
} else { 
    amLR.setRepeating(AlarmManager.RTC_WAKEUP, 
      System.currentTimeMillis(), interval, piLR); 
} 
+0

setAndAllowWhileIdle: можно ли использовать этот метод для повторного сигнала тревоги для определенного времени (например, 1 минута)? –

+0

да, вы можете изменить интервал. –

+0

Я проверил код ниже, но будильник не запускается после первого начального запуска, ********************************* ***** если (Build.VERSION.SDK_INT> Build.VERSION_CODES.LOLLIPOP_MR1) { \t loAlarmManager.setAndAllowWhileIdle (AlarmManager.RTC_WAKEUP, foInterval, loOperation); } иначе, если (Build.VERSION.SDK_INT> Build.VERSION_CODES.JELLY_BEAN_MR2) { \t loAlarmManager.setInexactRepeating (AlarmManager.RTC_WAKEUP, foTriggerAt, foInterval, loOperation); } else { \t loAlarmManager.setRepeating (AlarmManager.RTC_WAKEUP, foTriggerAt, foInterval, loOperation); } –

0

Начиная с KitKat, были внесены изменения в AlarmManager для улучшения устройства срок службы батареи. Время, в течение которого срабатывает сигнализация, является менее точным. Если вы хотите, чтобы ваши сигналы тревоги срабатывали в течение нескольких минут от запланированного времени, вам нужно будет изменить способ использования AlarmManager.

Для KitKat (API 19) и более поздних версий время, указанное в setRepeating(), неточно, как описано в documentation. Документы также отметить:

Если ваше приложение нуждается в точных сроках поставки, то он должен использовать разовые точные сигналы тревоги, перепланирование каждый раз.

Вы указываете, что аварийные сигналы не срабатывают, когда приложение не работает. Поскольку период для ваших сигналов тревоги составляет одну неделю, может быть большая разница между запланированным временем и фактическим временем срабатывания будильника. documentation указывает: первый триггер

ваш сигнал тревоги не будет до запрашиваемого времени, но это не может произойти в течение почти полного интервала после этого времени.

Я подозреваю, что с вашим текущим кодом вы в конце концов увидите огонь по тревоге, но, возможно, придется ждать очень долгое время после ожидаемого времени.

Ваш пересмотренный код, вероятно, должен будет использовать setWindow().

Marshmallow представил режим Doze, который дополнительно изменяет планирование аварийных сигналов. Как заметил в своем ответе @Andy, чтобы получить поведенческое поведение, которое вы хотите на Marshmallow и более поздних устройствах, вам нужно будет использовать setExactAndAllowWhileIdle().

Две другие вещи, которые необходимо исправить. Предполагается, что ваш PendingIntents должен использовать флаг PendingIntent.FLAG_UPDATE_CURRENT.В вашем приемнике флаг Intent.FLAG_ACTIVITY_NEW_TASK принадлежит к intent_1, а не pi.