Android 应用程序生命周期:也许是无限的?

发布于 2024-12-22 16:02:02 字数 700 浏览 4 评论 0原文

我正在开发一个应用程序,旨在将 Android 手机转换为无需用户操作即可运行的远程设备。当时,应用程序是由一个 Activity 创建的,该 Activity 设置 AlarmManager 每 X 分钟执行一次服务(项目内的类)。

所有这些工作正常,但偶尔连续运行 5-6 天后应用程序崩溃(目前我不知道为什么,因为我现在无法拿到手机)。这不是连接问题(我知道)并且手机仍在运行(插入交流电源)。我唯一可以假设的是应用程序已关闭。

我不认为这是由于错误造成的,因为预调试不会给我任何错误。

所以我必须假设 android 已经终止了该活动(系统需要更多内存?)并且正如图像所解释的那样,没有办法备份它。

流程图

但我有一个疑问:在我的应用程序中,活动并不重要,因为所有工作都是由服务。该服务本身由警报管理器调用,并且在两次调用之间的时间内,该服务由 StopSelf() 终止。

就我而言,系统可能会终止我的警报管理器服务计划?

我该怎么做才能让警报管理器永远启动服务?

注意:目前还存在 WAKE LOCK,但这仅考虑服务的执行!我希望您已经了解该服务由警报管理器每 x 分钟调用一次,然后终止...我想无限期地执行此操作)

[我没有发布源代码,因为太长了]

I'm developing an app designed to transform an android phone into a remote device running without user action. At the time the app is made by an Activity that sets AlarmManager to execute a service (class inside project) every X minutes.

All this works OK, but occasionally after 5-6 DAYS continuosly running the application crashes (currently I don't know why, because i can't get the phone now). It isn't a connection problem (I know) and the phone is still running (plugged into AC). The only thing that i can suppose is that the application is down.

I don't think that this is due to a bug, because the prew debugging doesn't give me any errors.

So I must suppose that android has killed the activity (system needs more memory?) and as the image explain there is no way to back it up.

Flow diagram

But I have a doubt: in my application the activity doesn't matter, because all the work is done by the service. The service itself is called by an Alarm Manager and in the time between two calls the service is terminated by StopSelf().

In my case the system may kill my alarm manager service schedule?

What can I do to have the service start up by Alarm Manager forever?

(ATTENTION: currently there is yet a WAKE LOCK but this consider only the execution of the service! I hope that you have understand that the service is called each x minutes by alarm manager and than terminated...i want to perform this operations for an indefinite time)

[I haven't posted the source code because is too long]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

倾听心声的旋律 2024-12-29 16:02:02

Lork,

在我自己解决了类似的问题之后,我可能会给你一些建议。我假设您将 Android 设备用作一种远程“嵌入式控制器”,它以最少的用户交互来执行其功能。我相信您已经完成了 95% 的任务,只需要进行一些轻微的架构更改即可。由于您没有提供代码,我只会用抽象术语进行解释,而不是给出代码示例。

CommonsWare 认为您需要使用 AlarmManager 是正确的,但我怀疑您已经知道这一点。
首先是一些背景评论,只是为了确保一切都可以理解。
AlarmManager 创建的警报存在于系统级别,也就是说,它们可以存在于创建它们的活动和应用程序的生命周期之外。如果你设置了一个闹钟,但不希望它在你的应用程序改变状态时关闭(例如在它被销毁之后),那么你可以使用alarmManager.cancel(pendingIntent)取消它——只需创建意图和闹钟管理器参数与Android相同会匹配闹钟)。
类似地,BroadcastReceiver 在系统级别注册(至少在manifest.xml 中声明),并且可以在创建它们的活动和应用程序的生命周期之外存在。同样,如果您想确保 BroadcastReceiver 不会响应应用程序更改状态后(例如在其被销毁后)发生的事件而触发,则需要在其代码中显式取消注册。如果它是以编程方式注册的,则使用 context.unregisterReceiver(broadcastReceiver);如果它是在清单中静态注册的,那就不太容易了——您必须使用 PackageManager 和 ComponentName 检索接收器(请参阅:Android - 如何取消注册清单中创建的接收器?) - 请记住,如果您再次需要它。

你说你已经设置好了闹钟。确保为闹钟类型指定 ELAPSED_REALTIME_WAKEUP 或 RTC_WAKUP,以确保即使手机处于“睡眠”模式时闹钟也会运行。
您还说您已经创建了关联的 BroadcastReceiver 来处理警报事件。 BroadcastReceiver 应该做最少的工作,因此您应该在单独的线程中或通过启动服务来处理任何处理。您选择启动服务并在完成后使用 stopSelf() 终止它,这样它就不会耗尽系统资源。到目前为止,一切都很好。

当应用程序运行时,这很好,但是,当您需要无限期可靠运行的东西时,您需要确保管理“异常”情况,其中它已暂停,设备正在“睡眠”,应用程序已崩溃/终止,或者设备已重新启动(以及您可能想到的任何其他异常情况)。以下是我发现的需要解决的问题:

第一:WakeLock 仅在 BroadcastReceiver 的 onReceive() 方法期间得到保证。终止后,即使您的服务尚未启动甚至尚未完成,设备也可能会返回“睡眠”状态,因此您需要创建一个 WakeLock,将其传递给服务并在停止服务之前释放它。 (注意:对于您的应用程序,您需要 PARTIAL_WAKE_LOCK)。使用 WakeLock 时要非常小心 – 确保仅在所需的最短时间内持有 WakeLock,并确保释放它,因为它的使用可能会导致电池过度消耗。请参阅 http://www.netmite.com/android/mydroid /development/pdk/docs/power_management.html 了解使用 WakeLocks 的示例。

第二:如果您在代码中重置闹钟(而不是定义自动重复的闹钟),请在 BroadcastReceiver 的 OnReceive() 方法中执行此操作,或者作为您启动的服务中的第一件事 – 这将确保闹钟重复,无论应用程序或设备的状态如何。

第三:确保您使用的任何上下文都是非空值。您可以使用 getApplicationContext() 动态获取服务中的上下文。否则,这可以通过将上下文从应用程序显式传递到警报并确保它一直通过 BroadcastReceiver 以及关联的线程和服务来实现。如果您在应用程序中静态存储了 Context,以便可以在任何地方检索它,那么如果应用程序已终止,这将返回空值。如果您使用 Context(例如检索资源、访问数据库等),并且它为空,则会导致空指针异常,并且 Service 或 BroadcastReceiver 将崩溃。我相信这是您的应用程序终止时广播接收器无法工作的最可能原因。

第四:您可能希望在您的服务或广播接收器中完全限定(.R.drawable.icon)或从传递的上下文生成的ResourceID(例如R.drawable.icon)中进行引用。我还没有发现这是必要的,但我怀疑这可能是谨慎的。

第五:实现一个单独的 BroadcastReceiver 来处理设备重启场景(ON_BOOT_COMPLETE 事件)。您可以让此接收器在适当的情况下重新启动应用程序,或者它可以启动一项服务来检查您的应用程序是否应该处于活动状态,设置任何所需的参数并设置相关警报,然后使用 stopSelf() 终止它,或者只是再次设置闹钟并让接收器处理这一切。请记住确保服务在其持续时间内具有 WakeLock,并在完成时释放 WakeLock。如果您不只是重新启动应用程序或服务(声明为应用程序的一部分),那么您还应该将正确的上下文作为类属性静态存储在您的 BroadcastReceiver 中(如果需要),以便可以访问资源。

您可能还需要考虑其他一些事情:
由于您的设置是远程的,我会认真考虑将任何持久数据存储在 SQLite 数据库表中。这将确保数据在应用程序终止和设备重新启动之间可恢复,而无需重新生成。
如果您的应用程序与服务器服务通信,请考虑使用推送通知进行服务器发起的通信,而不是让应用程序定期轮询。推送通知还可以用于“唤醒并启动服务和应用程序”,因此可以用作远程机制的一部分来查询设备和应用程序的状态。这种方法也更加节能和及时。
在代码中的关键点将信息发布到 LogCat 以进行调试。如果应用程序终止,则 adb 停止跟踪接收器和服务运行的源代码,但 LogCat 继续运行,因此可用于检查代码和变量值的路径。

其他人可能有更好的方法来解决这些问题或其他一些建议(我当然很高兴看到其他意见),但我希望这些想法有帮助,祝你好运!

Lork,

After wrestling with a similar issues myself, I may have some pointers for you. I assume that you are using your Android device as a sort of remote ‘embedded controller’, which performs its functions with minimum user interaction. I believe that you are 95% there and just need to make some slight architectural changes. As you have not provided code, I’ll just explain in abstract terms rather than give code examples.

CommonsWare is correct that you need to use AlarmManager, but I suspect you already knew that.
A couple of background comments first, just to make sure that everything is understandable.
Alarms created by AlarmManager exist at the system level, that is they can exist beyond the lifecycle of the activity and application that created them. If you set an alarm but don’t want it to go off if your app changes state (for example after it has been destroyed), then you can cancel it using alarmManager.cancel(pendingIntent) – just create the intents and alarm manager with the same parameters and Android will match the alarm).
Similarly, BroadcastReceivers are registered at the system level (at least if they are declared in manifest.xml) and can exist beyond the lifecycle of the activity and application that created them. Again if you want to ensure that a BroadcastReceiver does not fire in response to an event occurring after your app has changed state (for example after it has been destroyed), you need to explicitly unregister in it code. If it was registered programmatically then use context.unregisterReceiver(broadcastReceiver); if it was registered statically in the Manifest its not so easy – you will have to retrieve the receiver using PackageManager and ComponentName (see: Android - how to unregister a receiver created in the manifest? ) - and remember that you will need to re-enable the receiver if you need it again.

You say you have already set up your alarm. Make sure you specify ELAPSED_REALTIME_WAKEUP or RTC_WAKUP for the alarm Type to ensure that it runs even when the phone is in ‘sleep’ mode.
You also say you have already created the associated BroadcastReceiver to handle to alarm event. The BroadcastReceiver should do a minimum of work, so you should handle any processing in a separate thread or by launching a Service. You opted to launch a Service and terminate it using stopSelf() when it has finished, so that it doesn’t use up system resources. So far so good.

This is fine when the app is running, however as you require something that runs reliably for an indefinite period, you need to ensure that you manage the 'exception' situations where it has paused, the device is ‘sleeping’, the app has crashed/terminated, or the device has rebooted (and any other exception scenarios you may think of). Here are the issues I have identified that you need to address:

First: WakeLock is only guaranteed for the duration of the onReceive() method of the BroadcastReceiver. After it has terminated, the device could go back to ‘sleep’ even if your Service has not started or even completed, so you need to create a WakeLock, pass it to the Service and release it before you stop the Service. (Note: for your application, you require a PARTIAL_WAKE_LOCK). Be very careful using WakeLocks – make sure you only hold a WakeLock for the minimum required time and ensure you release it, as it’s use can lead to excessive battery drain). See http://www.netmite.com/android/mydroid/development/pdk/docs/power_management.html for an example of using WakeLocks.

Second: If you reset your alarm in code (rather than defining an automatically repeating one), do this in the OnReceive() method of the BroadcastReceiver or as the first thing in the Service you have launched – this will ensure that the alarm repeats, irrespective of the state of the application or device.

Third: Make sure that any Contexts you use are going to be non-null values. You can dynamically fetch the context in the Service using getApplicationContext(). Otherwise this can be achieved by EXPLICITLY passing the Context from your application to the alarm and make sure it is passed all the way through the BroadcastReceiver, and associated threads and Services. If you have statically stored Context in your application so you can retrieve it anywhere, then this will return a null value if the application has terminated. If you use the Context (for example to retrieve a resource, access a database etc), and it is null, it will cause a null pointer exception and the Service or BroadcastReceiver will crash. I believe this is the most likely reason for your Broadcast receivers not to be working when your app has terminated.

Fourth: You may wish to make references to ResourceIDs (e.g. R.drawable.icon) in your Service or BroadcastReceiver fully qualified (. R.drawable.icon) or generated from the passed Context. I haven’t yet found this to be necessary, but I suspect it may be prudent.

Fifth: Implement a separate BroadcastReceiver to handle a device reboot scenario (ON_BOOT_COMPLETE event). You could get this receiver to re-launch the app if appropriate or it could launch a service to check that your app is supposed to be active, set up any required parameters and set up the relevant alarms, then terminate it using stopSelf(), or just set the alarm again and let that receiver handle it all. Remember to ensure the service has a WakeLock for its duration and to release the WakeLock when it is complete. If you don’t just relaunch the app, or a Service (declared as part of your application) then you should also statically store the correct Context as a class attribute in your BroadcastReceiver, if you need it, so that it is available to access resources.

A couple of other things you may wish to consider:
As your set up is remote, I would seriously consider storing any persistent data in SQLite database tables. This will ensure that data is recoverable between application terminations and device reboots, without having to regenerate it.
If your application communicates with a server service, consider using push notifications for server initiated communication, rather than have the app periodically poll. Push Notifications can also be used to ‘wake up and launch services and apps’, so could be used as part of a remote mechanism to query the status of the device and your application. This approach is also more power efficient and timely.
Post information to LogCat at key points in your code for debugging. If the application terminates, then adb stops tracking the source code running for the receiver and service, but LogCat continues to function, so can be used to check the path through the code and variable values.

Other people may have better ways to address these issues or some other pointers (I would certainly be very happy to see other input), but I hope these ideas are helpful and good luck!

本宫微胖 2024-12-29 16:02:02

AlarmManager 与服务一起使用的目的是启动一个将短暂运行的服务,然后该服务消失(例如,IntentService)。如果您打算尝试拥有永久的服务,则不需要 AlarmManager,并且您的服务在一段时间后被 Android 关闭。

如果您将应用重写为不需要需要永久服务,而是按照预期使用AlarmManager,那么您应该具有更好的生存能力。

The point behind using AlarmManager with a service is to start up a service that will run briefly, then the service goes away (e.g., an IntentService). If you are going to try to have an everlasting service, you do not need AlarmManager, and your service will be shut down by Android after some period of time.

If you rewrite your app to not need an everlasting service, but rather use AlarmManager as it was intended, you should have better survivability.

找个人就嫁了吧 2024-12-29 16:02:02

我相信洛克想要实现的目标与我也在努力解决的问题类似。
他希望警报管理器触发一个广播接收器来处理警报,即使它所属的应用程序已终止(例如由 Android 操作系统终止)。

例如:应用程序设置一个警报,其类型为 ELAPSED_REALTIME_WAKEUP 或 RTC_WAKUP,并有一个广播接收器在警报触发时通过引用应用程序上下文和广播接收器类的 Intent 来处理它。接收器在应用程序清单中声明为 a。

正常情况下,当应用程序正在运行或暂停时,当警报响起时,广播接收器被触发,唤醒设备并根据需要恢复应用程序,并处理警报。
但是,如果应用程序已被终止(例如被操作系统终止),则警报仍然会响起(因为它仍然注册),但广播接收器不会被触发,并且 LogCat 显示空指针异常,(我假设是因为对应用程序的引用不再位于内存中)。即使 Context 已被传递,这种情况也会发生。

我(我假设洛克)在这里错过了一个简单的策略吗?还是不可能?广播接收器可以单独存在并在必要时触发应用程序吗?

我一直在尝试的一个不完美的策略是将所有应用程序数据访问移至内容提供程序中,并拥有一个单独的低配置应用程序,该应用程序仅实现广播接收器 - 触发服务来完成工作并访问它的应用程序数据需要通过内容提供商。这仍然会被操作系统终止,但可能性较小。

I believe that what Lork wants to achieve is similar to something I am also wrestling with.
He wants the alarm manager to trigger a broadcast receiver that will handle the alarm, even when the application it is part of, has been terminated (for example by the Android OS).

For example: The application sets an alarm, with a type of ELAPSED_REALTIME_WAKEUP or RTC_WAKUP and has a Broadcast Receiver to handle it when it fires, via an Intent which references the application context and the Broadcast receiver class. The receiver is declared as a in the application manifest.

Under normal circumstances, when the application is running or paused, when the alarm goes off, the Broadcast Receiver is triggered, waking up the device and resuming the application as necessary, and the alarm in handled.
However, if the application has been killed (for example by the OS), then the alarm will still go off (as it is still registered) but the Broadcast Receiver will not be triggered and LogCat shows a null pointer exception, (I assume because the reference to the application is no longer in memory). This will occur, even if the Context has been passed.

Am I (and I assume Lork) missing an easy strategy here? Or is it not possible? Can a broadcast receiver exist on its own and trigger the app if necessary?

One, imperfect strategy I have been toying with, is to move all the app data access into a Content Provider, and have a separate low profile app which just implements the broadcast receiver – triggering a service to do the work and accessing the application data it requires via the Content Provider. This would still be subject to being terminated by the OS, but would be less likely.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文