Android设计:后台长时间运行的服务还是AlarmManager?

5
我正在开发一款应用程序,它将定期监测电池状态、Wi-Fi连接和位置数据,并将结果写入文件(稍后发送到服务器)。在安装应用程序时,监视应该被禁用 - 但是用户启用它后应该在重新启动后仍然存在。经过大量阅读,我意识到基本上有两个选择:
1.子类化Service并从我的Activity中启动它。将其设置为前台、STICKY等,希望它不会被Android杀死 - 并且要注意如果Android重新创建它(实际上应该有3个服务,因此它们之间的同步可能会很混乱)。在服务中启动一个线程(我想不需要执行器),并让它Thread.sleep(REGULAR_INTERVAL)。唤醒,收集数据,将它们写入文件。广播收集的信息,并在我的Activity运行时显示它(它将已注册广播接收器)。反复这个过程while(true)。有一种方法可以中断这个过程。
2.使我的Activity向AlarmManager注册PendingIntent - 它将每隔REGULAR_INTERVAL运行一次。我还没有深入研究这种方法的技术细节,但我希望我能够让这个PendingIntent创建并运行IntentService(这似乎是正确的方法 - 免费获得线程机制以及自动关闭)。欢迎为这种方法提供一些框架代码。
我认为在两种情况下都必须注册引导接收器以检查共享首选项(已经完成了此操作),并且在情况1中启动服务,而在情况2中注册闹钟事件的接收器并设置闹钟管理器 - 这是我需要一些框架代码的部分。
所以 - 在我开始构建之前 - 哪种方法更好?
简而言之 - 应用程序应监视一些手机属性并将它们写入文件,直到用户选择关闭它。

如果您持续保持一个 Service 来收集某些数据,可能会消耗用户手机的电量,这样做可能会让用户对您产生不满。建议使用第二种方法,即使用 IntentService 并在需要时添加额外的 WakeLocks(可以查看 CommonsWare 的 WakefullIntentService)。 - user
@Luksprog:谢谢 - 在接收闹钟的广播接收器中,我需要锁吗?(仍在研究应该如何实现)? - Mr_and_Mrs_D
为什么要投负票? - Mr_and_Mrs_D
我没有给你的问题投反对票,但是可能有其他人不喜欢它。不要太在意这个。 - user
@Luksprog:没问题,我不认为是你的错:D 我讨厌没有原因的负评,而且这也不是一个糟糕的问题 - 明白吗。 - Mr_and_Mrs_D
3个回答

6

如果是情况2,则需要为闹钟事件注册一个接收器并设置闹钟管理器

您的接收器将已经通过清单文件进行了注册。

哪种方法更好?

AlarmManager,假设REGULAR_INTERVAL通常相当长(例如,超过几分钟)。理想情况下,该间隔应该是可由用户配置的。

如果您打算即使在设备睡眠时也要执行此操作,则选项#1根本无法工作,除非您一直保持WakeLock,这会导致用户想用霰弹枪朝您的脸射击。

可以提供此方法的一些基本代码吗?

这里有一个示例应用程序,演示了如何使用AlarmManager来处理非_WAKEUP闹钟(即,只需要在设备已经因其他原因唤醒时发生这些事件)。

这里有一个示例应用程序,演示了如何使用AlarmManager来处理_WAKEUP闹钟,并使用我的WakefulIntentServiceWakefulIntentService(或类似的服务)是必需的,因为AlarmManager不能让设备保持唤醒状态太长时间(仅足够BroadcastReceiveronReceive()方法被调用),因此您需要采取其他措施使设备保持唤醒状态足够长的时间以完成工作。理论上,您的工作可能足够快,可以只在BroadcastReceiveronReceive()方法中完成,而无需使用WakefulIntentService。但是,每次都会进行磁盘I/O操作,最好不要在调用onReceive()的主应用程序线程上执行此操作。当您要上传数据时,如果您也希望在后台中执行此操作,则可能仍然需要WakefulIntentService


谢谢 - 为什么要在清单中注册BroadcastReceiver(而不是启动接收器 - 这个必须存在)?这难道不意味着它会一直被注册 - 导致一些额外的开销吗?而对于BootReceiver -> '是否启用监控?(注册一个接收器进行警报;设置警报): 返回'似乎更经济。另外,AlarmReceiver会在我的主UI线程中运行吗?这将在我的活动(只是显示收集的数据并允许启用/禁用监控)处于活跃状态时发生 - 是这样吗?否则就没有UI线程(或者没有区别)- 我错了吗? - Mr_and_Mrs_D
@Mr_and_Mrs_D:“为什么要在清单中注册BroadcastReceiver”--否则,您需要一直保留一个组件(例如Service),这就是切换到“AlarmManager”的原因。您不希望一直占用内存。“这难道不意味着它会一直注册 - 导致一些开销吗?”--它只会被您的AlarmManager使用。“同时AlarmReceiver会在我的主UI线程上运行吗?”-- BroadcastReceiveronReceive()方法在主应用程序线程上调用。 - CommonsWare
@Mr_and_Mrs_D:“否则就没有UI线程”——总会有一个“UI线程”,更准确地说是“主应用程序线程”。如果您在主应用程序线程上花费太多时间,即使是从onReceive()开始,Android也会终止您的操作。 - CommonsWare
好的 - 我需要研究一下BRs - 我原以为如果我在引导接收器或者在我的应用程序中注册接收器,每当用户启用监视功能时,我就可以了。我会查看发布的代码并回来寻求更多帮助 - 因为有许多小细节逃脱了我的注意 :) - Mr_and_Mrs_D
@CommonsWare。您有没有想过像WhatsApp、Facebook这样的应用是如何实现几乎实时且不会消耗太多电池的呢?您能否推荐一些相关的示例应用程序?我非常喜欢您的书籍和博客,如果您能撰写一篇相关的博客文章将是非常棒的。我发现很多人都感到困惑(包括我),并看到了您在Stack Overflow上的所有答案。 - Harshit Bangar

1

0

根据循环任务的长度,您可以选择几种方法之一。本问题讨论了它们 - 在Android中安排重复任务

当任务休眠时间为15分钟或更长时,使用AlarmManager非常方便。该模式是众所周知的。


@CommonsWare:我有类似的情况需要每隔1分钟执行一些任务(GPS定位)。我在我的主活动中使用Handler来实现,这会对我的应用程序产生什么影响? - Tushar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接