2016-06-21 8 views
10

Я звоню в фоновом режиме Service с интервалом в 30 минут, чтобы прочитать широту/долготу текущего местоположения и отправить его на сервер с помощью POST API.Аварийный сигнал тревоги AlarmManager, случайно отсутствующий, когда телефон не используется

Я использую setRepeating() метод AlarmManager класс для планирования тревоги каждые 30 минут. Но несколько раз сигнал тревоги пропускается, и обслуживание не вызывается. Чтобы отслеживать, вызван ли сигнал или нет, каждые 30 минут я создал файл Log.txt на SD-карте. За каждый раз, когда в файле Log.txt записывается тревога, называемая записью для текущего времени. Но, сравнив 4-5 файлов Log.txt устройств, я заметил, что для некоторых устройств будильник не вызывает onCreate() метод UserTrackingReceiver.java (Фоновая служба). Полный фрагмент кода, упомянутый ниже.

При запуске приложения registerUserTrackingReceiver() метод был вызов, который находится ниже:

public static void registerUserTrackingReceiver(Context context) { 
     try { 
      Intent intent = new Intent(context, UserTrackingReceiver.class); 

      boolean alarmUp = (PendingIntent.getService(context, 1001, intent, PendingIntent.FLAG_NO_CREATE) == null); 

      if (alarmUp) { 
       Calendar calendar = Calendar.getInstance(); 

       if (calendar.get(Calendar.MINUTE) > 0 && calendar.get(Calendar.MINUTE) <= 30) { 
        calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY)); 
        calendar.set(Calendar.MINUTE, 30); 
        calendar.set(Calendar.SECOND, 0); 
       } else if (calendar.get(Calendar.MINUTE) > 30) { 
        if (calendar.get(Calendar.HOUR_OF_DAY) == 23) { 
         calendar.set(Calendar.HOUR_OF_DAY, 0); 
        } else { 
         calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) + 1); 
        } 
        calendar.set(Calendar.MINUTE, 0); 
        calendar.set(Calendar.SECOND, 0); 
       } else { 
        calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY)); 
        calendar.set(Calendar.MINUTE, 0); 
        calendar.set(Calendar.SECOND, 0); 
       } 

       PendingIntent sender = PendingIntent.getService(context, 1001, intent, 0); 
       AlarmManager alarmManager = (AlarmManager) context.getSystemService(context.ALARM_SERVICE); 
       alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 
         AlarmManager.INTERVAL_HALF_HOUR, sender); 
      } 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
} 

UserTrackingReceiver.java ниже:

public class UserTrackingReceiver extends Service 
     implements LocationListener, 
     GoogleApiClient.ConnectionCallbacks, 
     GoogleApiClient.OnConnectionFailedListener { 

    @Override 
    public void onCreate() { 
     super.onCreate(); 

     Calendar calendar = Calendar.getInstance(); 
     Util.appendLog("Tracking Alarm Called on: " + calendar.get(Calendar.HOUR_OF_DAY) + " : " + calendar.get(Calendar.MINUTE) + " : " + calendar.get(Calendar.SECOND)); 
     stopSelf(); 
    } 
} 

В Util.java есть appendLog() метод, который ниже:

public static void appendLog(String text) { 

     String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath(); 

     File logFile = new File(baseDir + "/" + Constant.AppNameSuper + "/log.txt"); 
     if (!logFile.exists()) { 
      try { 
       logFile.createNewFile(); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
     try { 
      //BufferedWriter for performance, true to set append to file flag 
      BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true)); 
      buf.append(text); 
      buf.newLine(); 
      buf.close(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
} 

Если тревога вызывается каждые 30 минут в соответствии с приведенным выше кодом, она должна быть записана в файле Log.txt в SDCARD. Но проблема в том, что он не может записывать файл журнала каждые 30 минут, что означает отсутствие тревоги. Что касается чтения в течение двух дней, я заметил, что будильник не пропадает в дневное время, так как пользователь постоянно использует свой телефон, но он пропускается ночью, когда телефон не используется.

Out поместить файлы с различными устройствами входа ниже:

Устройство A Log.txt

  • Tracking Alarm Призвал: 0: 0: 31 (начало от 12: 00 Ночь)
  • Трекинг Тревога, вызванная: 1: 10: 27
  • Трекинг Тревога, вызванная: 3: 5: 25
  • Отслеживание сигнализации Призвал: 6: 55: Alarm 31
  • Tracking Призвал: 7: 0: 6
  • Tracking Alarm Призвал: 7: 30: 0
  • Tracking Alarm Призвал: 8: 0 : 6
  • Отслеживание сигнализации призвал: 8: 30: 0
  • Tracking Alarm призвал: 9: 0: 6
  • Tracking Alarm призвал: 9: 30: 0
  • Tracking Alarm призвал: 10 : 0: 0

Устройство B Журнал.TXT

  • следящий Alarm Призвал: 0: 0: 27 (Start С 12:00 Night)
  • Tracking Alarm Призвал: 0: 30: 1
  • Tracking Alarm Призвал: 1 : 0: 1
  • следящий Alarm призвал: 1: 30: Alarm 2
  • Tracking призвал: 2: 0: 1
  • Tracking Alarm призвал: 2: 30: 1
  • Отслеживание сигнализации Призвал: 3: 0: 1
  • Отслеживание сигнализации Призвал: 3: 30: 1
  • Tracking Alarm Призвал: 4: 0: 1
  • Tracking Alarm Призвал: 4: 30: 29
  • Отслеживание сигнализации призвал: 5: 0: 1
  • Tracking Alarm призвал: 5: 30: 2
  • Tracking Alarm призвал: 6: 0: 30
  • Tracking Alarm призвал: 6: 30 : 1
  • Отслеживание Al рука Призвал: 7: 0: 1
  • Tracking Alarm Призвал: 7: 30: 1
  • Tracking Alarm Призвал: 8: 0: 1
  • Tracking Alarm Призвал: 8: 30: 1
  • Отслеживание сигнализации Вызывается: 9: 0: 32
  • Tracking Alarm призвал: 9: 30: 1

устройств C Log.TXT

  • следящий Alarm Призвал: 0: 0: 7 (Start С 12:00 Night)
  • Tracking Alarm Призвал: 0: 30: 3
  • Tracking Alarm Призвал: 1 : 0: 6
  • Отслеживание сигнализации призвал: 1: 30: Alarm 1
  • Tracking призвал: 2: 0: 32
  • Tracking Alarm призвал: 2: 30: 3
  • Отслеживание сигнализации Призвал: 3: 1: Alarm 50
  • Tracking Призвал: 3: 30: 5
  • Tracking Alarm Призвал: 4: 1: 58
  • Tracking Alarm Призвал: 4: 31: 14
  • Отслеживание сигнализации призвал: 5: 0: 1
  • Tracking Alarm призвал: 5: 30: 1
  • Tracking Alarm призвал: 6: 2: 1
  • Tracking Alarm призвал: 6: 30 : 1
  • Отслеживание A LARM Призвал: 7: 0: 1
  • Отслеживание сигнализации Призвал: 7: 30: 1
  • Tracking Alarm Призвал: 8: 0: 1
  • Tracking Alarm Призвал: 8: 30: 4
  • Отслеживание сигнализации Вызывается: 9: 1: 44
  • Tracking Alarm призвал: 9: 30: 1

устройств D Log.TXT

  • следящий Alarm Призвал: 0: 1: 25 (Start С 12:00 Night)
  • Tracking Alarm Призвал: 0: 30: 0
  • Tracking Alarm Призвал: 1 : 31: 41
  • Отслеживание сигнализации призвал: 2: 39: 52
  • Tracking Alarm призвал: 3: 0: 25
  • Tracking Alarm призвал: 3: 30: 58
  • Отслеживание сигнализации Призвал: 4: 0: Alarm 25
  • Tracking Призвал: 4: 30: 56
  • Tracking Alarm Призвал: 5: 30: 51
  • Tracking Alarm Призвал: 7: 18: 55
  • Отслеживание сигнализации призвал: 7: 30: 0
  • Tracking Alarm призвал: 8: 0: 25
  • Tracking Alarm призвал: 8: 30: 43
  • Tracking Alarm призвал: 9: 0 : 3
  • T ломают Alarm Вызывается: 9: 30: Alarm 25
  • Tracking Призвал: 10: 0: 25
  • Tracking Alarm Призвал: 10: 30: 4
  • Tracking Alarm Призвал: 11: 1: 52
  • следящий Alarm призвал: 11: 30: 27
  • Tracking Alarm призвал: 12: 1: 6⁠⁠⁠⁠
+0

это звучит как ограничение режима доз в Android MM. Вы должны быть уверены, что ваше приложение включено в белый список и использует 'setAndAllowWhileIdle()', добавленный в API23 .... – Opiatefuchs

+0

Спасибо за редактирование @ user13 – himCream

ответ

8

Проблема может быть в вашем PendingIntent, вызывающем Service. Устройство может вернуться в режим сна до того, как ваш Service закончит выполнение (или даже запуск).

Вместо этого я предлагаю вам использовать BroadcastReceiver (так как WakeLock гарантируется в течение onReceive()).

Приобретать в onReceive()WakeLock, начните Service оттуда и освободить WakeLock от Service, когда это необходимо.

Чтобы упростить этот процесс, вы можете использовать WakefulBroadcastReceiver вспомогательный класс:

  1. вызов PendingIntent.getBroadcast() вместо PendingIntent.getService().
  2. Запустить IntentService от onReceive() по телефону WakefulBroadcastReceiver.startWakefulService().
  3. Сделайте свой материал в onHandleIntent() и позвоните по телефону WakefulBroadcastReceiver.completeWakefulIntent() по завершении.

Например, BroadcastReceiver, что начинается бодрствующим Service:

public class ExampleReceiver extends BroadcastReceiver { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
     Intent wakefulServiceIntent = new Intent(context, 
      ExampleWakefulService.class); 

     WakefulBroadcastReceiver.startWakefulService(context, 
      wakefulServiceIntent); 
    } 
} 

И Service:

public class ExampleWakefulService extends IntentService { 

    private static final String NAME = "com.example.ExampleWakefulService"; 

    public ExampleWakefulService() { 
     super(NAME); 
    } 

    @Override 
    protected void onHandleIntent(Intent intent) { 

     // doing stuff 

     WakefulBroadcastReceiver.completeWakefulIntent(intent); 
    } 
} 

Кроме того, проверьте this article от руководства разработчика по поддержанию устройства просыпаются.

Уровень API 23+ Вы должны иметь дело с Doze.

documentation От:

Чтобы помочь с планирования аварийных сигналов, Android 6,0 ​​(уровень API 23) представляет два новых AlarmManager методы: setAndAllowWhileIdle() и setExactAndAllowWhileIdle(). С помощью этих методов вы можете установить аварийные сигналы , которые будут срабатывать, даже если устройство находится в режиме Doze.

К сожалению, нет никакой альтернативы для setRepeating(), поэтому у вас есть два варианта:

  • Установить точные сигналы тревоги (используя соответствующий метод в зависимости от уровня API устройства, проверить this answer для примера) и перепланировать их каждый раз, когда они стреляют.
  • Whitelist ваше приложение (не рекомендуется из-за строгой политики пересмотра Google).
1

Вы должны использовать BroadcastReceiver и wakelock надежно сделать это происходят, когда устройство простаивает. Кроме того, обратите внимание, что начиная с сигналов API 19 по умолчанию неточно, что будет играть в этом. если вы ориентируетесь на API 21 или новее, подумайте об использовании JobScheduler. Аналогично этому сообщению Alarm Manager with 2 pending intents only 1 works?

0

Согласно Android разработчика document Примечание:

Примечание: по API 19, все повторяющиеся сигналы являются неточными. Если ваше приложение нуждается в точном сроке доставки, оно должно использовать одноразовые точные аварийные сигналы , пересматривая каждый раз, как описано выше. Legacy приложения, чья targetSdkVersion ранее API 19 будет , продолжают иметь все свои аварийные сигналы, включая повторяющиеся сигналы тревоги, считаются точными.