IntentService runs in the background even after the onHandleIntent finishes - android

I'm building an application that has a widget and a button in the widget launches an IntentService.
The onHandleIntent() runs some code and then raises a toast through a handler.
After I click the button in the widget, I see the toast and I know that onHandleIntent finished.
But when I look in the background services I still see my app there.
As a user, I get very annoyed when apps always run on the background and wasting my precious RAM. My widget doesn't need to run in the background because my widget doesn't update ever (the update rate in the xml is 0).
So how come that the service is still running? How can I stop it?
IntentService code:
public class WidgetCheckService extends IntentService {
private int mAppWidgetId;
Handler mHandler = new Handler();
public SalaryWidgetCheckService(String name) {
super("laceService");
}
public SalaryWidgetCheckService() {
super("laceService");
}
#Override
protected void onHandleIntent(Intent intent) {
// Badass code
mHandler.post(new DisplayToast(getString(R.string.widget_service_check_in_success_toast_text).replace("LACE", lace)));
else mHandler.post(new DisplayToast(getString(R.string.widget_service_check_out_success_toast_text).replace("LACE", lace)));
}
private class DisplayToast implements Runnable{
String mText;
public DisplayToast(String text){
mText = text;
}
public void run(){
Toast.makeText(WidgetCheckService.this, mText, Toast.LENGTH_SHORT).show();
}
}
}
Thanks, Elad.

But when I look in the background services I still see my app there.
Your process is not automatically terminated when the service ends. Android will keep your process running until it needs to free up the RAM for other apps, just in case it happens to need to run something from your app again. This is no different than any other app on Android.

Related

self destructing an android app after certain amount of time

i currently work on an app that needs a lot of battery in order to support background gps tracking. my experience shows that people just forget about the app runnning in the background when they dont really need the tracking anymore. therefore i setup some code that should close the application after 4 hours.
public class SelfDestructor {
private static SelfDestructor instance;
private final long IDLE_TIME_UNTIL_AUTO_DESTRUCT = 4 * 60 * 60 * 1000; // 4 hours
private Handler handler;
private Runnable closeApp = new Runnable() {
#Override
public void run() {
System.exit(0);
}
};
public static SelfDestructor getInstance() {
if (SelfDestructor.instance == null) {
SelfDestructor.instance = new SelfDestructor();
}
return SelfDestructor.instance;
}
public void keepAlive() {
if (handler == null) {
handler = new Handler();
}
handler.removeCallbacks(closeApp);
handler.postDelayed(closeApp, IDLE_TIME_UNTIL_AUTO_DESTRUCT);
}
}
now in my main activity i call keepAlive().
#Override
protected void onResume() {
super.onResume();
SelfDestructor.getInstance().keepAlive();
}
#Override
protected void onStart() {
super.onStart();
SelfDestructor.getInstance().keepAlive();
}
now if i set the time to an hours or so and debug the that functionality everything works fine. if i set the time to 4 hours the System.exit(0); is never called. i am assuming the app thread with the close callback is just put on hold by the android system after a while and therefore will not be executed anymore while gps will continue to run. any ideas how to properly get this to work?
handler and postDelayed are not suited for long timers. At most they should be used within a few seconds and personally I think I never used one for anything more than 2 seconds.
Said all that, Android have an appropriate class for "stuff that should happen after a long time", it's called AlarmManager: http://developer.android.com/reference/android/app/AlarmManager.html
you can get the references to the system service AlarmManager by calling Context.getSystemService(Context.ALARM_SERVICE)
and then set it by calling am.set(AlarmManager.ELAPSED_REALTIME, IDLE_TIME_UNTIL_AUTO_DESTRUCT, operation)
the operation is a PendingIntent to a BroadcastReceiver that you register in the AndroidManifest.xml via the <receiver> tag. Then you do the close application code inside this broadcast receiver.
Also I should add that it's NEVER good to call System.exit(0);, as this just destroy the VM without much of a warning. It's a better, more organised/structured shut down if you pass a command to the Service that is holding the GPS (I believe you're running a service), then this service will cancel the GPS request, and call stopSelf();

What happens to Threads started in Android Service when Android restarts the Service?

I have a Service like this (this is not the actual Service, it's just for describing my problem).
public class UploadService {
private BlockingQueue<UploadData> queue = null;
private UploadInfoReceiver receiver = null;
public void onStart(...) {
queue = new LinkedBlockingQueue<UploadData>();
(new Processor()).start();
// creating and reigtering receiver
}
public void onDestroy() {
queue.add(new ServiceDestroyedData());
// unregistering the receiver
}
private class Processor extends Thread() {
public void run() {
while (true) {
UploadData data = queue.take();
if (data instanceof ServiceDestroyedData) {
return;
}
// processing data
}
}
}
private class UploadInfoReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
queue.add(new UploadData(/* getting data from intent */));
}
}
}
And my problem is that if I do something like this in my App:
if (!isUploadServiceRunning()) {
// start the Service
}
Then it starts the Service, but when I move my App to the background and open task manager (android 4.2.2), and kill the app, Android restart my Service, and I can see that it creates a whole new instance of it, and I can see that onDestroy never gets called for the previous Service instance. And I also can see that the instance of the previous Processor Thread is no longer running. How can this be? If onDestroy never gets called how does Android know that it should stop my Thread?
Thanks for your answers.
Android will kill off anything that it finds that is attached to your apps classloader when you select force stop from the menu. Think kill -9 on Linux. There will be no nice callbacks to any onDestroy methods, the system will just end everything.
Now for your service:
while(true) should really NEVER be used. It will instantly kill the battery and will not do any work 99% of the time anyway.
You area already using a receiver, you can just put your while logic into there and once the upload is done call the next upload and so on. There is absolutely no need for the loop.

Android sticky background service restarts application after it's closed

I'm developing an Android app that needs to do some updating in the background every hour or so. I have a background service which I've made Sticky. And I'm using Timer.scheduleAtFixedRate to schedule the updates.
This seems to work fine. But I've noticed that when I close the app, the next time the scheduled update runs, it causes Application.onCreate to get called again.
This is a problem because Application.onCreate is where I'm grabbing data down from APIs ready to display to the user. I don't want this to happen in the background.
Is this expected behaviour? If so, perhaps I need to add a check in onCreate to see if the app is in the foreground first? Or maybe I've got something set up wrong?
Thanks!
p.s. It's a Galaxy Samsung running Jelly Bean 4.2.1
Background Service code:
#EService
public class BackgroundService extends Service {
...
private Timer timer = new Timer();
private void performUpdate() {
// Do the stuff here that we need to do on a schedule...
Log.i(LOG_CONTEXT, "Perform scheduled update");
...
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(LOG_CONTEXT, "Background thread started");
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
performUpdate();
}
}, 0, UPDATE_INTERVAL);
// Sticky means service will continue running until explicitly stopped
return START_STICKY;
}
#Override
public void onDestroy() {
Log.d(LOG_CONTEXT, "Background thread stopped");
timer.cancel();
}
}
Application code:
#EApplication
public class MyApplication extends Application {
...
#Override
public void onCreate() {
super.onCreate();
initApp();
}
private void initApp() {
// This is where I want to do stuff when the app is actually
// opened by the user, not every time the background service
// update occurs!
Log.i(LOG_CONTEXT, "Initialise. Why does this happen again after app's closed?");
...
}
...
Log:
12-09 16:28:15.828: I/MyApplication(3049): Initialise. Why does this happen again after app's closed?
[Now I close the app, by pressing the Recent Apps menu button and swiping it away]
12-09 16:28:16.015: I/BackgroundService(3049): Perform scheduled update
12-09 16:28:33.875: I/MyApplication(3080): Initialise. Why does this happen again after app's closed?
Your service runs as a part of your application, so the application is created for it.
Most apps do not need to extend Application. Without seeing all of your code, I'm pretty sure you don't need to either. Just extend Activity for the class that displays stuff to the user and do the API stuff in that. That will not be created when the service runs.

CalledFromWrongThreadException using Service IPC connection

I'm using the tutorial here to develop a Service that is (right now) just running a TimerTask to do System.out.println("tick") every second. My code is exactly like the code on the site, aside from some name changes. Everything works (the Service runs, outputs "tick") if I don't try to pass a String from the Service to the Activity.
What I'm trying to accomplish is to get a TextView in the main Activity to be updated with a String received from the Service. I have an append(String) method working fine that will update the TextView with new text. So in my Service's TimerTask I've added listener.handleMessage("tick") and my Activity implements the listener functionality:
public void handleMessage(String msg) throws RemoteException {
append(msg);
}
When I run the application, System.out shows a "tick", then a stacktrace with the CalledFromWrongThreadException, pointing to the append() method as the source of the problem.
I know there's a few questions about this Exception, but most of them concern Thread and Handler issues; I couldn't find anything about Services. Anyone know if this is possible?
Solution
Extend Runnable:
class MyRunnable implements Runnable {
private String msg;
public MyRunnable(String msg) {
this.msg = msg;
}
public void run() {
appendNewline(msg);
}
}
and replace the callback with a call to global Handler:
public void handleMessage(String msg) throws RemoteException {
handler.post(new MyRunnable(msg));
}
Updates to the ui have to occur on the ui thread and not a background thread (like that of the timer). To update the ui, declare a member variable of type Handler and call the post method, passing a new runnable instance that can update your text view. This is a decent tutorial

Locking screen in Android speeds up game

I'm updating my game using a Handler posting a delayed Runnable.
public class Example implements Runnable
{
Handler handler;
public Example()
{
handler = new Handler();
handler.postDelayed(this,10);
}
public void run()
{
handler.postDelayed(this,10);
}
}
Whenever I press the lock screen button and then resume the game, it runs much faster than it is supposed to. Every time I lock the screen and resume, it runs faster and faster. However, if I restart the activity or finish and then re-open the activity, it runs at normal speed again. Help please.
Thanks in advance.
What seems to be happening is every time you lock your screen and then resume it is making another Runnable on top of the Runnable you already have doubling your run thus making the thread go faster and faster everytime, you need to somehow pause your thread something like thread.sleep() or something similar when you lock your screen so when you resume you aren't recreating a new Runnable and instead just starting from where you left off in your thread.
If you are making a new Runnable in an onCreate method. It is going to get called anytime the phone is rotated, or when the phone resumes etc. and thus is why you are probably having this issue. The reason it doesn't happen after you finish() your activity or close your app is because when you restart the app, that Runnable is going to get created once, until you start locking the phone and resuming again etc.
you may also want to look at an inner class you can use to help handle your threads:
public class YourClass extends Activity {
public void yourUpdateMethod() {
runOnUiThread(new Runnable() {
public void run() {
new YourUpdateClass().execute(0, null, null);
}
});
}
private class YourUpdateClass extends AsyncTask<Integer, Void, Void> {
#Override
protected synchronized Void doInBackground(Integer... index) {
return null;
}
#Override
protected synchronized void onPostExecute(Void result) {
//your statements here
}
}
}
This might help handle threads that have to be paused/restarted/resumed or whatever a little better. More info here: http://developer.android.com/reference/android/os/AsyncTask.html
Dunno how it would work in a game though, didn't play around with that.
Good Luck, hope this helps.

Categories

Resources