Android sticky background service restarts application after it's closed - android

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.

Related

Android best use AsyncTask, Service or other

I'm a student writing some app to understand and study Android Development.
I'm trying to write an app the should work like this:
MapActivity:
Show a map with user position and open Access point in a range.
User and AP position should be received by the "MainClass".
MainClass:
This should do the main work. It should get user position, get open access point from db and insert into the db new open AP found with WifiManager scans.
Now, the MainClass should work in background, on user agree, even if the app is closed.
My questions are:
Should I do MainClass stuff on a new thread or on the UI thread?
Should MainClass be an AsyncTask, Service or other? please tell me why too.
the scan operation return a scan that get executed in a registered receiver. Does it run on UI thread or in a new one?
Thanks in advance.
UPDATE;
So, if i'm not messing what are you saying, the service should look like this:
public class MainService extends Service {
Thread mainThread;
#Override
public void onCreate() {
mainThread = new Thread(new Runnable() {
#Override
public void run() {
....
mainOperation();
....
}
});
mainThread.setPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
mainThread.run();
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
does START_STICKY on kill call onStartCommand or onCreate?
Should I do MainClass stuff on a new thread or on the UI thread?
Answer:
You should do on the background thread (new thread) because android does not allow network tasks on UI thread also if you do time taking operation on UI thread UI will freeze
Should MainClass be an AsyncTask, Service or other? please tell me why too.
Answer:
As you clearly said your requirement (MainClass should work in background) you need to use Service because service runs in background even when your app is killed
You should use MainClass.java stuff into a background thread. i.e., Service
Service will trigger data through Broadcast receiver.
Broadcast receiver will send data to MapActivity.java. Registered receiver's onReceive() method always run in the UI thread.
If you want to run MainClass.java stuff in foreground you can use MVP pattern. You should do your stuff into presentation layer.
Background Service will be the best and only solution for your requirements I guess. Because you want your operation to keep running even when your app is closed.

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 Service shutting down when function works longer than (about) 15 seconds

I have a service which works with LongPoll and when I receive my data everything is OK, but when I don't receive data, rather I receive empty result (long polling max time == 25 sec) my service sometimes turning off manually (and I don't see it in list of services).
So, how to keep this service (..always..) running?
Recursive function, which works with long polling and at first calls in service's onCreate() (structure):
//"u" is "new utils()".
public class myservice extends Service {
public static boolean started=false;
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "created qweqwe", Toast.LENGTH_LONG).show();
longpoll();
this.started=true;
}
#Override
public void onDestroy() {
super.onDestroy();
this.started=false;
}
private String url = "http://example.com/lp.php";
private void longpoll() {
try {
String resp = u.getData(url); //max time of working u.getData(lpurl) - 25s.
if (resp.length()>0) doSmthWithData(resp); //It works fine
} catch(Exception e) {}
longpoll();
}
}
So, how to keep this service (..always..) running?
Tactically, based on the "15 seconds" in your question title, my guess is that you are doing this long poll on the main application thread. You need to do it on a background thread.
Strategically, you cannot keep a service "always running". You can use startForeground() to reduce the odds of your service being automatically destroyed, but the user and the OS can still get rid of your process (along with its service) at any time for any reason. Many users do not like services that are "always running" because of the resources they waste, and therefore will attack developers of such services with task killers and low ratings on the Play Store.

IntentService runs in the background even after the onHandleIntent finishes

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.

Categories

Resources