Надежность диспетчера аварийных сигналов

Я боролся с этой проблемой в течение нескольких дней. Я также проверил документацию и несколько тем, но не нашел решения/объяснения.
Я тестирую свое приложение на LG p500, но я также провел несколько тестов на Droid и получил тот же результат.

Мое приложение использует AlarmHandler для планирования будильника. Приложение корректно работает на эмуляторе, а также на устройстве до тех пор, пока на устройстве не будет достаточно свободной памяти. Когда я запускаю несколько других приложений на устройстве, а памяти мало, будильник больше не срабатывает. Как только я останавливаю «другое» приложение, будильник снова работает нормально.

Позвольте мне сообщить тест и результат.

  1. Я установил будильник в своем приложении через 10 минут.
  2. Я запускаю несколько приложений (браузер, карта Google, Gmail, K9Mail,....)
  3. Я запускаю catlog, чтобы увидеть журнал моего приложения
  4. Подождите 15 минут, не работая по телефону
  5. Через 10 минут должен сработать будильник, но ничего не происходит, пока я не разбужу свой телефон нажатием кнопки.
  6. Когда я просыпаю свой телефон, сразу же срабатывает будильник, и происходят все уведомления.
  7. Я останавливаю «другое» приложение, которое я ранее запускал (браузер, карта Google,...)
  8. Снова установите будильник через 10 минут.
  9. Я запускаю catlog, чтобы увидеть журнал моего приложения
  10. Подождите, не работая по телефону
  11. Через 10 минут срабатывает будильник, и я получаю уведомление.

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

Глядя на журнал моего приложения, я не вижу никаких ошибок / исключений, но похоже, что когда в системе мало памяти, что-то происходит, и широковещательный приемник не запускается, пока телефон не будет разбужен через клавиатуру. Как только я просыпаю телефон, запускается приемник, и все уведомления происходят.

Вот код, который я использовал:

Получатель:

public class NotificationReceiver extends BroadcastReceiver
{
public static final String LOG_TAG = "YAAS - Notification Receiver";

@Override
public void onReceive(Context context, Intent intent)
{
    ScheduleActivityService.acquireStaticLock(context);
    Log.i(LOG_TAG, "Received alarm - id: " + intent.getIntExtra("id", -1));
    Intent intent2 = new Intent(context, ScheduleActivityService.class);
    intent2.putExtra("id", intent.getIntExtra("id", -1));
    context.startService(intent2);
}
}

Сервис

public class ScheduleActivityService extends Service
{
public static final String LOCK_NAME_STATIC="it.hp.yaas.AppService.Static";
public static final String LOG_TAG = "YAAS - ActivityService";
private static PowerManager.WakeLock lockStatic = null;

private final IBinder mBinder = new LocalBinder();

public class LocalBinder extends Binder
{
    public ScheduleActivityService getService()
    {
        return ScheduleActivityService.this;
    }
}

@Override
public IBinder onBind(Intent intent)
{
    return mBinder;
}

public static void acquireStaticLock(Context context) {
    getLock(context).acquire();
}

synchronized private static PowerManager.WakeLock getLock(Context context)
{
    if (lockStatic == null)
    {
        PowerManager mgr = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        lockStatic = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOCK_NAME_STATIC);
        lockStatic.setReferenceCounted(true);
    }
    return(lockStatic);
}

/**
 * This method is called when an alarm fires that is its alarm time is reached.
 * The system assume that the alarm fired match the alarm time of the first
 * activity.
 * @param intent intent fired
 * @param flag
 * @param startId
 */
@Override
public int onStartCommand(Intent intent, int flag, int startId)
{
    super.onStartCommand(intent, flag, startId);
    try {
        Log.i(LOG_TAG, "Alarm fired: " + startId + " - id: " + intent.getIntExtra("id", -1));
        AlarmHandler.getInstance().onAlarmFired(intent.getIntExtra("id", -1));
    }
    finally { getLock(this).release(); }
    return START_STICKY;
}

@Override
public void onDestroy()
{
    super.onDestroy();
    Log.i(LOG_TAG,  "Destroy");
}
}

Фрагмент кода из AlarmHandler, подпрограммы, вызываемой для планирования тревоги:

    public synchronized void onAlarmFired(int alarmId)
{
    scheduledAlarmId = -1;
    Alarm alarmFired = pop();
    if (alarmFired == null) return;
    Log.i(LOG_TAG, "onAlarmFired (Alarm: " + alarmFired + ") at (time: " + Utilities.convertDate(new Date(), "HH:mm:ss") + ")");
    notifyAlarmListener(alarmFired);
    if (alarmFired.reschedule(null) != null) add(alarmFired);
    Alarm alarm = peek();
    if (alarm != null && scheduledAlarmId != alarm.getId()) scheduleEvent(alarm);
}

/**
 * Schedule an alarm through AlarmManager that trigger next activity notification
 * @param alarm alarm to be scheduled
 */
private void scheduleEvent(Alarm alarm)
{
    Log.i(LOG_TAG, "scheduleEvent - (Alarm: " + alarm + ")");
    Intent intent = new Intent(context, NotificationReceiver.class);
    intent.putExtra("id", alarm.getId());
    // In reality, you would want to have a static variable for the request code instead of 192837
    PendingIntent sender = PendingIntent.getBroadcast(context, 192837, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    // Get the AlarmManager service
    AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
    am.set(AlarmManager.RTC_WAKEUP, alarm.getTime().getTime(), sender);
    scheduledAlarmId = alarm.getId();
}

И, наконец, это кусок файла манифеста:

    <activity android:name=".ListActivity"
          android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    </activity>

    <activity android:name=".EditActivity"/>

    <activity android:name=".SettingsActivity"/>

    <service android:name="ScheduleActivityService"
             android:label="YAAS Service"/>

    <receiver  android:name="NotificationReceiver" />

person Marco Cravero    schedule 08.08.2011    source источник
comment
Вы решили эту проблему?   -  person Ilya Kogan    schedule 18.11.2012
comment
См. это devmaze.wordpress.com/2011/12/05/activating-applications   -  person AZ_    schedule 23.11.2012
comment
@AZ_ ссылка битая :-(   -  person Dominique    schedule 13.08.2016
comment
к сожалению не знаю почему   -  person AZ_    schedule 15.08.2016


Ответы (2)


Вы уверены, что ваш процесс не будет убит, когда вы запускаете все эти приложения? Если это произойдет, установленные вами будильники умрут вместе с ним. Не совсем ясно, кто и когда планирует будильник в вашем коде, но если это служба, поскольку она липкая, в конечном итоге она будет перезапущена, и в какой-то момент вы получите сигнал тревоги (когда вы разбудите устройство).

Простой способ проверить, какие тревоги зарегистрированы в разных точках вашего тестирования:

# adb shell dumpsys alarm
person Nikolay Elenkov    schedule 08.08.2011
comment
См. документы, один из моментов использования AlarmManager заключается в том, что вашему приложению/процессу не нужно запускать developer.android.com/reference/android/app/AlarmManager.html - person superfell; 08.08.2011
comment
Тем не менее, процессы, регистрирующие тревоги через AlarmManager, не должны оставаться активными для срабатывания тревог, поэтому даже если процесс убит (более чем вероятно, что это так), тревоги все равно должны срабатывать. Это цель AlarmManager и методологии тревог. - person Austin Hanson; 08.08.2011
comment
Его не обязательно запускать, но если процесс выдает исключение или завершается, предупреждения сбрасываются. - person Nikolay Elenkov; 08.08.2011
comment
Спасибо всем. Если мой процесс выдает исключение, ошибка должна быть зарегистрирована в файле журнала, и я не вижу никаких ошибок, используя catlog. Аварийные сигналы планируются действием, но, поскольку мой код обрабатывает очередь аварийных сигналов, и я отправляю в AlarmManager только первый, когда аварийный сигнал срабатывает, мой код ищет в очереди следующий аварийный сигнал и планирует его, и это делается с помощью оказание услуг. Во всяком случае, как я знаю, но я не эксперт по Android, потому что моя служба расширяет службу, она работает в том же процессе и потоке действий. Я сделал этот выбор, потому что при срабатывании сигнализации мне нужно обновить пользовательский интерфейс. - person Marco Cravero; 09.08.2011
comment
Попробуйте провести простой эксперимент по получению полного пробуждения с параметрами PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE. - person Royston Pinto; 20.11.2012

Мой код очень похож на ваш в приложении для будильника, которое я написал и регулярно использую. Я не смог воспроизвести проблему, которую вы описываете. Кажется, я не могу перевести свой телефон в состояние крайне низкого уровня памяти. Я открыл все приложения, которые я установил, и у меня все еще есть 260 МБ свободного места на моем HTC Rezound.

В качестве меры предосторожности в своем приложении я использовал alarmmanager.setRepeating() вместо .set(). Я установил интервал повторения на 20 секунд. Я передал идентификатор тревоги в качестве дополнительного намерения, как и вы. Когда моя служба запускается, она немедленно отменяет ожидающее намерение, используя идентификатор тревоги. Моя логика заключается в том, что если по какой-либо причине мой будильник не срабатывает, он будет продолжать попытки каждые 20 секунд, пока не сработает.

person Jason Hessley    schedule 24.11.2012