【问题标题】:How to update the data send to a service using intent when service is started by alarm manager?警报管理器启动服务时,如何使用意图更新发送到服务的数据?
【发布时间】:2012-09-24 18:04:28
【问题描述】:

我正在编写一个 Android 应用程序,用户可以在其中选择几只股票来观察,如果符合预定义的警报条件,就会收到警报。库存数据保存到自定义 Parcelable 类“警报”的 5 个对象(每个库存和条件一个对象)。定期数据更新是通过由 AlarmManager 启动的服务完成的。警报对象通过将它们放入 Intent 中传递给服务,该 Intent 被放入 AlarmManager 的 PendingIntent 中。

    Intent intent = new Intent(this, UpdateService.class);
    Bundle b = new Bundle();
    saveAlertsToBundle(b);      
    intent.putExtras(b);
    intent.setData(Uri.parse("updateManager"));
    PendingIntent pendIntent = PendingIntent.getService(this,0,intent,0);

    // 1min intervall
    long intervall = DateUtils.MINUTE_IN_MILLIS * 1;
    // time of first start
    long firstStartDelay = DateUtils.SECOND_IN_MILLIS * 30;
    long firstStart = System.currentTimeMillis() + firstStartDelay;

    AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    // kill running
    am.cancel(pendIntent);
    //start new
    am.setRepeating(AlarmManager.RTC_WAKEUP,firstStart,intervall,pendIntent);

我的问题是:

第一次启动服务时,只有一个警报对象传递给服务,一切正常。一旦存在更多警报对象,它们也需要传递给服务,但这不适用于上面的代码。服务不会收到带有额外警报对象的更新意图,而只会收到只有一个警报对象的初始意图。上面的代码正确地创建了一个包含附加警报对象的 Intent,但它们从未访问过服务。

所以我的问题是,如何将更新后的意图传递给已经运行的 AlarmManager。

我已经尝试停止 AlarmManager(在 // kill running 注释处的行)并重新启动它,但这不起作用。也许是因为意图与他被创建时不持有相同的警报对象?我试图通过在意图的数据部分设置一个 uri 来解决这个问题,但这也没有帮助。

感谢您的帮助。

【问题讨论】:

    标签: android service android-intent alarmmanager


    【解决方案1】:

    您的问题是PendingIntent 的工作方式。系统管理PengingIntents 的池。当您的代码执行时:

    PendingIntent pendIntent = PendingIntent.getService(this,0,intent,0);
    

    这会导致系统搜索与您传入的参数匹配的PendingIntent(在本例中为您的Intent。但是,PendingIntent 使用的匹配算法仅比较 @ 的某些字段987654327@ 来确定它是否是您正在寻找的那个。特别是,它不比较额外内容。所以这意味着在您创建了第一个 PendingIntent 之后,对 @987654329 的调用@ 将始终从池中返回相同的 PendingIntent(而不是创建一个新的,这是您想要的)。

    为了在每次调用PendingIntent.getService() 时创建一个新的PendingIntent,请尝试使传递给调用的参数唯一,如下所示:

    int requestCode = (int) System.currentTimeMillis(); // Create unique request code
    PendingIntent pendIntent = PendingIntent.getService(this, requestCode, intent, 0);
    

    由于每次调用PendingIntent.getService()requestCode 都会有所不同,这应该可以解决您的问题。

    编辑基于以下 OP 的 cmets

    您想取消现有警报并使用新数据创建一个新警报。在这种情况下,您不需要使用唯一标识符,因为您只想在池中拥有一个 PendingIntent。但是,您想为此更改数据。试试这个:

    // Create a PendingIntent (or update the existing PendingIntent with new values
    PendingIntent pendIntent = PendingIntent.getService(this, 0, intent,
                          PendingIntent.FLAG_UPDATE_CURRENT);
    
    AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    // cancel any pending alarms
    am.cancel(pendIntent);
    //start new
    am.setRepeating(AlarmManager.RTC_WAKEUP,firstStart,intervall,pendIntent);
    

    【讨论】:

    • 感谢您的帮助,这解决了问题,但又创建了一个新问题。额外的警报对象被传递给服务,但作为额外的 AlarmManager 控制的服务,已经运行的 AlarmManager 继续运行。因此,每次我添加警报对象时,AlarmManager 的数量都会增加。这意味着我有一个针对一个警报对象,一个针对两个,一个针对三个,等等。我认为如果只有一个具有当前数量的现有警报会更好,所以我仍然需要停止旧的 AlarmManager。通过调用 stopSelf() 停止服务。
    • 好的。我不确定你到底想做什么。根据此评论,听起来您想取消现有警报并使用新参数创建一个新警报。我将为此编辑我的答案。
    • 这非常有效。所以我所缺少的只是正确的标志,看来。感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多