报警管理器可靠性

时间:2011-08-08 15:42:18

标签: android alarmmanager

我几天来一直在努力解决这个问题。我还检查了文档和几个主题,但没有找到任何解决方案/解释。
我在LG p500上测试我的应用程序,但我也在Droid上进行了一些测试,得到了相同的结果。

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

让我报告测试和结果。

  1. 我在10分钟后对我的申请发出警报。
  2. 我启动了几个应用程序(浏览器,谷歌地图,gmail,K9邮件,......)
  3. 我启动了catlog以查看我的应用程序的日志
  4. 等待15分钟而不使用手机
  5. 10分钟后,警报应该被触发,但在我按下按钮
  6. 唤醒手机之前没有任何事情发生
  7. 当我唤醒手机时,警报立刻响起,所有的通知都会发生。
  8. 我停止了之前启动的“其他”应用程序(浏览器,Google地图,...)
  9. 10分钟后再次设置闹钟
  10. 我启动了catlog以查看我的应用程序的日志
  11. 等待不通电话
  12. 10分钟后,警报响起,我收到通知。
  13. 我做了几次测试,得到了相同的结果 然后我尝试使用我之前从市场上下载的“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" />
    

2 个答案:

答案 0 :(得分:5)

您是否确定在启动所有这些应用程序时您的进程不会被杀死?如果是这样,您设置的警报将随之消失。在您的代码中安排警报的人和时间并不完全清楚,但如果它是服务,由于它是粘性的,它最终会重新启动,并且您将在某个时刻(当您唤醒设备时)收到警报。

检查在测试的不同点注册的警报的简便方法:

# adb shell dumpsys alarm

答案 1 :(得分:0)

我的代码与您在我编写和定期使用的闹钟应用程序上非常相似。我无法重现您描述的问题。我似乎无法将手机置于极低的内存状态。我打开了我安装的每个应用程序,并且仍然可以在我的HTC Rezound上免费使用260M。

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