October 25, 2014

Code Pollution: Background Control

In the Code Pollution series, I’ll be writing about topics where a coding anti-pattern may work tactically for an individual application, but strategically will be bad for Android as a whole, just as pollution may benefit one firm while harming many others.

In the previous post in the Code Pollution series, I pointed out how it is possible for background processes, such as those driven by AlarmManager, can wind up with foreground priority and impact real-time games. Poor frame rates is not the only reason that a user might be concerned about your application’s use of background operations, though.

A popular application category on the Android Market is the so-called “task killer” app. These apps exploit some Android API loopholes to kill off everything associated with an application: services, activities, AlarmManager alarms, etc. Many developers decry these tools, complaining that users then gripe that the developers’ apps do not work, when it was the users themselves (with the task killer’s help) that broke the apps in the first place.

While I agree that the task killers are probably overused, there is also little question that some Android apps are not “good citizens” when it comes to their use of background operations. Perhaps they try to have everlasting services, or perhaps they poll too frequently, or try to do too much in the foreground windows, or something.

In the end, user satisfaction is dependent upon Android apps being responsible in their use of background operations. Here are some tips on how to stay in your users’ good graces.

First, avoid those everlasting services. Users get nervous if they see your service hanging around in memory all the time, particularly if they think they are experiencing performance issues. Users might use a task killer to shut down your service, or they might use the Settings application in newer versions of Android. To the greatest extent possible, architect your application to run on a scheduled basis using the AlarmManager, rather than assuming you will be successful in keeping your service in RAM indefinitely.

Therefore, you might decide that you want the AlarmManager to invoke your service frequently, such as every minute. That may make sense to you. It might not make sense to your users. Make your alarm periods configurable. Even if you elect to choose an aggressive default, let the user choose something that is less frequent. You can cancel and re-establish your alarm when the user changes the setting.

One special case of configurable alarm periods is infinity — in other words, allow the user to disable your background operations altogether. Yes, background work is sexy. On the other hand, as of the time of this writing, iPhone does not support background operations for third-party applications. The fact that iPhone apps can be successful without background operations means you can be successful as well by letting the user choose to forgo such background work. You might want to pop up a dialog or something to warn the user of lost functionality if they disable it, but still let them disable it.

Understand that, even with this configurability, the user might still nuke your app via a task killer. Do not fight the user. The user knows what the user wants. It is up to you to deliver. If the user wants your background operations disabled and chooses to do that via a task killer than your preference activity, so be it. In fact, if you have a good way to check to see that you were killed (e.g., the time gap between your last background run and now is well over the alarm period), you might even pop up a dialog saying something to the effect of “I see you used a task killer to get rid of me. Would you like my background operations to be disabled?”. That way, you turn a negative (user feeling a task killer is appropriate for your app) into a positive (you demonstrate that you are aware of their interest and can be configured the way they want).

That is one facet of a bigger issue: do not assume you know best. Yes, you like your app. Yes, you think all users will like your app and want to use it the same way you do. That rarely works out in reality. Even some things you might consider essential may not be. For example, one argument for using an everlasting service is a VOIP app — after all, there is no other way to receive an incoming call if there is no service with a socket watching for calls from the SIP server. However, that assumes the user wants incoming calls. Perhaps they do not, wanting VOIP just for outbound calls. If you do not let this be configurable, they will be inclined to smack your app around via a task killer to get rid of the service.

Some mobile operating systems preclude background operations. Android does not, but that does not mean background operations are always a good thing. Let the user decide. The more developers do this, the less of a problem task killers will pose for everyone.