【问题标题】:IntentService, PendingIntent, and AlarmManager: Cannot keep process running indefinitely?IntentService、PendingIntent 和 AlarmManager:不能让进程无限期地运行?
【发布时间】:2014-12-08 19:28:03
【问题描述】:

我有一个非常简单的应用程序,它在后台运行两个服务,使用 IntentService 和 AlarmManager。一个是“消息”服务,它发送 JSON 请求并解析响应,另一个从 LocationManager 轮询位置。这里的要求是它们在一定间隔内无限期地运行,直到用户使用按钮手动停止 - 即使设备的屏幕已经好几天没有打开了。服务绝不能停止。电池寿命不是问题。

我的最低支持 API 是 4.1,我正在 4.1、4.2 和 4.4 设备上进行测试。在我的 Nexus 7 和 GPad 上,分别是 4.4.4 和 4.4.2,服务将无限期地运行并按预期工作。在运行 4.2 的 Galaxy Tab 3 上,设备似乎在 8 小时后进入睡眠状态。左右不活动,然后会退出报告位置和投票。 4.1 的设备似乎也是如此。

有了这种预感,我将其添加到消息传递服务中以手动唤醒 CPU。这个每 60 秒运行一次。所以我希望它可以防止设备进入睡眠状态。

@Override
protected void onHandleIntent(Intent intent)
{                       
    PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
    PowerManager.WakeLock wl = pm.newWakeLock(
            PowerManager.PARTIAL_WAKE_LOCK, 
            "com.service.MESSAGE_SERVICE_WAKE_LOCK");

    wl.acquire();

    //poll for messages via JSON    

    wl.release();               
}

像这样设置AlarmManager(pi = PendingIntent...传入IntentService类):

alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pollInterval, pi);

这似乎为我自己的测试解决了问题,并且设备在 4.4 和 4.2 上始终为我报告位置。但是,4.1 测试人员报告说,大约 8 小时后它仍然会在他们身上睡觉。我还在朋友的 Galaxy S5 (4.4.2) 上进行了测试,几个小时后它就退出了报告位置。

这是我的第一个应用程序,这部分特别令人沮丧。难道我做错了什么?知道为什么这些服务可能会停止运行吗?很高兴提供更多代码,如果有帮助的话……我想我会从这个开始,至少。

【问题讨论】:

  • “这里的要求是它们一直运行到手动停止”——请定义“运行”和“手动停止”。您的意思是“这里的要求是警报不断触发并且服务有机会完成工作,直到手动停止”?这将是合理的,您的问题将是可以解决的。
  • 用户可以随时摆脱后台服务。当然,用户也可以摆脱您的警报,但这不太可能。由于内存不足,操作系统也会终止您的进程,这是简单说明您的服务需要运行以响应AlarmManager 事件的路线的另一个好处,因为一旦这些服务完成了它们的工作,它进程是否终止无关紧要。
  • “你有明确的例子吗?” -- 我在AlarmManager 上有a whole chapter,包括一些样本,例如this one。拉里正在讨论的内容很准确,现在我已经确认这几乎是您想要的行为。
  • 您是否在清单中注册了接收方? LogCat 是否显示任何值得注意的内容?
  • 我会在AlarmManager 上选择cancel()。你不应该两者都需要。

标签: android alarmmanager android-pendingintent locationmanager intentservice


【解决方案1】:

使用PendingIntent 表示Service 的警报不能保证让设备保持唤醒足够长的时间以启动或恢复Service。对于IntentService,服务在处理完所有排队的Intent 对象后会自动终止。您需要将PendingIntent 用于BroadcastReceiver,它采用WakeLock 并启动您的Service。然后,您的Service 可以在完成工作后释放唤醒锁,让设备重新进入睡眠状态。

【讨论】:

  • 你有一个明确的例子吗?在我上面的代码中,每次调用 onHandleIntent 时,我确实向广播接收器发送了一个 Intent。无论如何,希望看到您所描述内容的简单代码示例。谢谢。
  • 你很幸运,我之前写过一篇关于这个的文章,并包含一个简单的测试应用程序来展示它。 po.st/7UpipA
  • “它需要一个 WakeLock 并启动你的服务。你的服务可以在完成工作后释放唤醒锁”——实现这一点的最简单方法是使用罐装解决方案,@987654322 @.
  • 是的,这正是 WakefulBroadcastReceiver 创建的目的。在我文章的示例代码中,我采用了一种稍微不同的方法,将唤醒锁放在应用程序的 Application 类中;但是,最终结果是一样的。
  • 有趣,我会研究一下 WakefulBroadcastReceiver。谢谢你们的帮助。
【解决方案2】:

如果您希望服务“始终”运行,则不应将其设为后台服务。

改为foreground service

前台服务是被认为是某种东西的服务 用户主动意识到,因此不是系统的候选者 在内存不足时杀死。

为了测试在操作系统内存不足时您的服务可以运行多长时间,您可以尝试this sample Ive made(我已发布here,并使用this library Ive made ),它使用越来越多的 RAM(真正的 RAM,而不是堆的 RAM)。它会导致操作系统杀死其他进程并最终杀死样本本身的进程。

如果您只想让您的服务每 X 小时/分钟运行一次,那么您根本不需要这个,而且您发现的似乎还可以。

【讨论】:

  • 这是一个有趣的方法。网络(即 JSON 请求)和 LocationManager 是否安全?这是我在这个应用程序中使用最多的两个功能。 “此示例”链接已损坏……但是,如果您修复它,我很想看看它。谢谢!
  • 你是对的。该链接由于某种原因无法正常工作,但该帖子还可以。转到帖子并在那里下载。它被称为 "MemoryConsumerTest.7z" 。该示例仅尝试向操作系统施加压力,因此您可以看到您的服务会发生什么并相应地处理它。关于安全性,对于您编写的内容使用前台服务是安全的,但您仍然需要处理服务因任何原因(内存太低)而被终止的情况。
  • 只有在主动向用户交付价值时才会运行服务:commonsware.com/blog/2014/07/27/role-services.html
  • @CommonsWare 好吧,这也取决于服务在做什么。我不确定他想做什么。也就是说,你是对的。我希望他通过阅读我提供的链接来理解他的服务将在前台运行意味着什么。
猜你喜欢
  • 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
相关资源
最近更新 更多