【问题标题】:Alarm Manager Reliability报警管理器可靠性
【发布时间】:2013-12-03 00:21:08
【问题描述】:

我已经为这个问题苦苦挣扎了好几天。我还检查了文档和几个主题,但没有找到任何解决方案/解释。
我正在 LG p500 上测试我的应用程序,但我也在 Droid 上做了一些测试,得到了相同的结果。

我的应用程序使用 AlarmHandler 来安排警报。应用程序在模拟器和设备上正常工作,直到设备有足够的可用内存。 当我在设备上启动其他几个应用程序并且内存不足时,警报将不再触发。一旦我停止“其他”应用程序,警报就会再次正常工作。

让我报告测试和结果。

  1. 10 分钟后,我在应用程序上设置了闹钟。
  2. 我启动了几个应用程序(浏览器、谷歌地图、gmail、K9Mail ......)
  3. 我启动 catlog 以查看我的应用程序的日志
  4. 等待 15 分钟,不要在手机上工作
  5. 10 分钟后应该会触发警报,但在我按下按钮唤醒手机之前什么都没有发生
  6. 当我唤醒手机时,警报会立即响起,所有通知都会发生。
  7. 我停止了之前启动的“其他”应用程序(浏览器、谷歌地图……)
  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();
}

最后这是一段 Manifest 文件:

    <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" />

【问题讨论】:

标签: android alarmmanager


【解决方案1】:

您确定在启动所有这些应用程序时您的进程不会被终止吗?如果是这样,您设置的警报将随之消失。目前尚不清楚谁以及何时在您的代码中安排警报,但如果是服务,因为它是粘性的,它最终会重新启动,并且您会在某个时候收到警报(当您唤醒设备时)。

一种检查在不同测试点注册了哪些警报的简单方法:

# adb shell dumpsys alarm

【讨论】:

  • 查看文档,使用 AlarmManager 的要点之一是您的应用程序/进程不需要运行developer.android.com/reference/android/app/AlarmManager.html
  • 通过 AlarmManager 注册警报的进程不必保持活动状态以触发警报,因此即使进程被终止(很可能是这样),警报仍应触发.这就是 AlarmManager 和警报方法的意图。
  • 它不需要运行,但如果进程抛出异常或被杀死,则清除警报。
  • 感谢大家。如果我的进程抛出异常,则应该在日志文件中记录一个错误,并且使用 catlog 看不到任何错误。警报是由一个活动安排的,但是,因为我的代码处理一个警报队列并且我只提交给 AlarmManager 的第一个警报,当警报触发时,我的代码在队列中查找下一个警报并安排它,这是由服务。无论如何,据我所知,但我不是安卓专家,因为我的服务扩展了服务,它在活动的同一进程和线程中运行。我做这个选择是因为当警报触发时我必须更新 UI。
  • 尝试使用参数 PowerManager.FULL_WAKE_LOCK | 获取完整唤醒锁的简单实验PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE。
【解决方案2】:

我的代码与您在我经常编写和使用的警报应用程序上的代码非常相似。我无法重现您描述的问题。我似乎无法让我的手机进入内存极低的状态。我打开了我安装的每个应用程序,但我的 HTC Rezound 上仍有 260M 的免费空间。

在我的应用程序中,我使用了alarmmanager.setRepeating() 而不是.set() 作为保护措施。我将重复间隔设置为 20 秒。就像您一样,我将警报 ID 作为额外的意图传递。当我的服务启动时,它会立即使用警报 ID 取消挂起的意图。我的逻辑是,如果由于任何原因我的警报失败,它将继续每 20 秒尝试一次,直到成功。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-27
    相关资源
    最近更新 更多