Android app running time: maybe it is infinite?

I am developing an application designed to convert an Android phone to a remote device that works without user intervention. At that time, when the application is created using Activity, which sets the AlarmManager to execute the service (class inside the project) every X minutes.

All this works fine, but sometimes after 5-6 DAYS of continuous launch the application crashes (at present I don’t know why, because I can’t get the phone now). This is not a connection problem (I know), and the phone is still working (connected to AC power). The only thing I can assume is that the application is not working.

I do not think that this is due to an error, because preliminary debugging does not give me any errors.

So, I have to assume that the android killed the activity (does the system need more memory?), And as the image explains, there is no way to support it.

Flow diagram

But I have doubts: in my application, activity does not matter, because all the work is performed by the service. The service itself is called by the alarm manager and during the time between two calls the service is interrupted by StopSelf ().

In my case, the system can kill the service schedule of the alarm manager?

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

(ATTENTION: at present there is still WAKE LOCK, but this only takes into account the service! I hope you understand that the service is called every x minutes by the alarm manager and stopped ... I want to perform these operations for an indefinite time)

[I did not send the source code because it is too long]

+4
source share
3 answers

Lork

After struggling with such problems myself, I may have some guidelines for you. I assume that you are using your Android device as a kind of remote “built-in controller” that performs its functions with minimal user interaction. I believe that you are 95% there, and you only need to slightly change the architectural changes. Since you did not provide the code, I will simply explain it in abstract terms, rather than provide code examples.

CommonsWare is correct that you need to use AlarmManager, but I suspect you already knew this. First, a couple of background comments, just to make sure everything is clear. Alarms created by AlarmManager exist at the system level, that is, they can exist outside the life cycle of the activity and the applications that created them. If you set an alarm but don’t want it to turn off if your application changes state (for example, after it was destroyed), you can cancel it with alarmManager.cancel (pendingIntent) - just create intentions and an alarm manager with the same parameters and Android will be alarmed). Similarly, BroadcastReceivers are registered at the system level (at least if they are declared in manifest.xml) and may exist outside the life cycle of the activity and the application that created them. Again, if you want to make sure that BroadcastReceiver does not fire in response to an event that occurred after your application changed its state (for example, after its destruction), you need to explicitly unregister the code in it. If it was registered programmatically, then use context.unregisterReceiver (broadcastReceiver); if it was registered statically in the manifest, it is not so simple - you will need to get the recipient using the PackageManager and ComponentName (see: Android - how to unregister the recipient created in the manifest? ) - and remember that you need to turn on the receiver again, if you need it.

You say you already set your alarm. Make sure you specify ELAPSED_REALTIME_WAKEUP or RTC_WAKUP for the type of alarm to make sure that it works even when the phone is in standby mode. You also say that you have already created the associated BroadcastReceiver to handle the alarm event. BroadcastReceiver should do a minimum of work, so you should process any processing in a separate thread or when the service starts. You decided to start the service and end it with stopSelf () when it ended so that it did not use system resources. So far so good.

This is normal when the application is running, however, since you need something that works reliably for an indefinite period of time, you need to make sure that you manage situations of “exception” when it is paused, the device is “sleeping”, the application crashes / terminates working or rebooting the device (and any other exception scenarios you might think of). Here are the problems that I have identified that you need to address:

First: WakeLock is only guaranteed for the duration of the onReceive () method of BroadcastReceiver. After its completion, the device may return to sleep mode even if your service was not started or even completed, so you need to create WakeLock, transfer it to the Service and release it before the service stops. (Note: for your application you need PARTIAL_WAKE_LOCK). Be careful with WakeLocks - make sure you only hold WakeLock for the minimum amount of time and make sure you release it, as using it 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 the code (rather than detecting it automatically), do it in the OnReceive () method of BroadcastReceiver or, as the first thing you run in the Service, this will ensure that the alarm is repeated, regardless of the state of the application or device .

Third: make sure that any contexts used are non-zero values. You can dynamically retrieve 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 that it goes all the way through BroadcastReceiver and its associated streams and Services. If you statically save the Context in your application so that it can be found anywhere, then this will return a null value if the application terminated. If you use a Context (for example, to get a resource, access to a database, etc.), and it is null, this will throw a null pointer exception, and the service or BroadcastReceiver will fail. I believe this is the most likely reason your Broadcast receivers will not work when your application terminates.

Fourth: you may want to reference the ResourceID (e.g. R.drawable.icon) in your Service or BroadcastReceiver in its entirety (R.drawable.icon) or generated from the passed Context. I have not yet found that this is necessary, but I suspect that this might be reasonable.

Fifth: Implement a separate BroadcastReceiver to handle the device reboot script (ON_BOOT_COMPLETE event). You can get this receiver to restart the application, if necessary, or it can start the service to check that your application should be active, configure any required parameters and configure the corresponding alarms, and then terminate it with stopSelf (), or just set the alarm again and let this receiver handle it all. Remember to make sure that the service has a Wake Wake for its duration and release WakeLock when it is completed. Unless you simply restart the application or service (declared as part of your application), you must also statically maintain the correct context as a class attribute in your BroadcastReceiver, if you need it so that it is accessible for access to resources.

A few other things you might want to consider: Since your setup is remote, I would seriously consider storing any persistent data in the SQLite database tables. This ensures that the data will be restored between the termination of the application and the reboot of the device, without the need for its regeneration. If your application interacts with a server service, consider using push notifications for server-initiated communication, rather than periodically polling the application. Push Notifications can also be used to “wake up and run services and applications,” so they can be used as part of a remote mechanism to query the status of the device and your application. This approach is also more efficient and timely. Send information to LogCat at key points in your code for debugging. If the application terminates, adb stops tracking the source code that is running for the recipient and the service, but LogCat continues to function, so it can be used to check the path through the code and variable values.

Other people may have better ways to solve these problems or some other pointers (I, of course, would be very happy to see other materials), but I hope these ideas will be useful and good luck!

+4
source

The point that uses AlarmManager with the service is to start the service, which will be executed for a short time, then the service will leave (for example, IntentService ). If you try to get an eternal service, you do not need AlarmManager , and your service will be disabled by Android after a while.

If you are rewriting your application so that it does not need an eternal service, but rather use the AlarmManager as it was intended, you should have better survivability.

0
source

I believe that what Lork wants is similar to what I also struggle with. He wants the alarm manager to launch a broadcast receiver that will process the alarm even when the application in which it is logged in has been terminated (for example, the Android OS).

For example: an application sets an alarm of type ELAPSED_REALTIME_WAKEUP or RTC_WAKUP and has a broadcast receiver to handle it when it fires, through Intent, which refers to the application context and 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 turns on, the device wakes up and the application resumes as needed, and the alarm is processed. However, if the application was killed (for example, by the operating system), then the alarm will still be disabled (since it is still registered), but the broadcast receiver will not start, and a null pointer exception will be displayed in LogCat (I assume that the link on the app is no longer in memory). This will happen even if Context has been passed.

Did I (and I guess Lork) miss the easy strategy here? Or is it impossible? Can a broadcast receiver exist on its own and run an application if necessary?

One, imperfect strategy that I worked with is to move all access to application data to the Content Provider and have a separate low-profile application that simply implements a broadcast receiver - starting a service to do work and accessing application data that required through the content provider. It will still be suspended by the OS, but will be less likely.

0
source

Source: https://habr.com/ru/post/1387620/


All Articles