Activity calles onStartCommand of service - android

I´ve got a background service, which pushes notifications. When you click on the notifications, my activity is opened, but the problem is, the onStartCommand is called then again, which propably could invoke another notification, which means I have a loop.
I´m using
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_NOT_STICKY;
}
also tried Service.START_STICKY with no effect.
In my manifest:
<service
android:name=".notification.NotificationService"
android:exported="false"></service>
what could cause a recall of onStartCommand?

Check your Activity code, sounds like your accidentally starting the Service.
There are some situations where this could happen like
it may be killed by the system if it is under heavy memory pressure.
If this happens, the system will later try to restart the service.
There Is another possibility this might happen. If you rotate your device your Activity will be killed and restarted all according to Android official docs Activity . Your Service will be launched again. Read the docs, save some time and headache. On this link Android official docs Activity, scroll down 2 laps and you see a picture of the lifecycle.

Related

Stop the Service on Destroy of Application

I am confused right now , about service concept of running and stopping:
what i want to do:
Start Location service at the very start of application.
Keep getting location updates and store them to shared preference
Stop the service in onDestroy of Application scope!
So far i have searched and studied we can only do following things with service(correct me if i'm wrong):
Stop the service automatically by binding it to related activities/fragments/views , when all of them destroyed service unbind itself automatically so we can call stopself method in unbind
return START_NOT_STICKY in onStartCommand to tell OS , don't recreate it , and create intent local service , after completion of some work it will destroy itself.
Stopping the service manually , by declaring it's intent in some kind of static scope and stopping the service in on onActivityDestroyed of Application class [I am not sure what will happen? , maybe service will destroy each time any activity will be destroyed ? or it will be destroyed only when overall application get's destroyed?]
Either way , i am bit confused and beat , been trying to adjust my Location service with given details for 2 days
If you start your Service using START_NOT_STICKY, then your app will kill your service once your entire application is closed from background i.e. you cleaned your app from home screen.
Here START_NOT_STICKY states that you need not recreate service in case it is been killed.
If this is not the case then you have to manually kill it by your self.
Like
Intent lintent = new Intent(context, LocationService.class);
context.stopService(lintent);
You can use this code at point where your application kills.
That's it. You are good to go with this.
First of all, launch the "LocationService" on your app start:
public class MyApp extends Application {
private static final String TAG = "MyApp";
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "App started up");
startService(new Intent(this, MyLocationService.class));
}
}
Second :
As you said, the Service should better run with the "START_NOT_STICKY" flag
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
Thrid:
Once the system kills your app, the Service will automatically be killed, so no problems at all.
There is no onDestroy() method on the Application object, the only similar event is onTerminated() and it is not being launched on production devices.
onTerminate
Added in API level 1 void onTerminate () This method is for use in
emulated process environments. It will never be called on a production
Android device, where processes are removed by simply killing them; no
user code (including this callback) is executed when doing so.
More information:
https://developer.android.com/reference/android/app/Application.html#onTerminate()
Btw, If you want the MyLocationService to send updates of the location to your app (when it is open), you should consider to use Otto or EventBus (I recommend you this last one because of the simplicity to use it). You can even configure the #Suscriber to receive updates of old retrieved locations if you want.
I will try to explain in a easiest way :)
There are two type of service
IntentService and Service
IntentService when started will kill itself once it treated the content of it onHandleIntent method
as for Service well this one will not end until you give it the command to do so even if your start it using the context of an activity. It will also stop when the application is stopped in an extreme case (by system (Settings/application/YourApp/stop app OR an app crash)
Easiest way is First of all start IntentService with AlarmManager at some repeating time (10 mintutes), then in onHandleIntent() get Location and store into preference.
No Need bind to your activity, the IntentService automatically stops itself after saved in preferences.
Yes you can stop the service in onDestroy() of the activity:
#Override
public void onDestroy(){
Log.v("SERVICE","Service killed");
service.stop();
super.onDestroy();
}

Android: Start my service when I close my app

Basically I have a service running to check my location every 30 minutes and when the location changes, pop up a basic notification. I only need this service when my app is closed (on stop/pause too). So im asking where should I start my service in my activity?
I want something similar as Facebook,Instagram and most of apps have... a service running from the background and when a notification pops up just open de app. While the app is open the service shouldnt do anything.
I tried onDestroy() method (in my MainActivity) but didnt work out, and onStop() method neither.
Do i explain myself?
Thanks!!
Recurring tasks should be scheduled using AlarmManager (or JobScheduler).
This is usually done in a BroadcastReceiver which reacts to BOOT_COMPLETED.
If you want to cancel such a job while your activity is active, call the respective methods on AlarmManager in onResume and onPause.
If you want your service to be running in the background at all times event after closing the app, you need to make your service STICKY and you can do that in the OnStartCommand
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
Note that it returns START_SICKY which tells the OS to recreate the service after it has enough memory and call onStartCommand() again with a null intent.
Read also about application:persistent which is "Whether or not the application should remain running at all times". This is more troublesome - System will try not to kill your app which will effect others in the system, you should be careful using it.

RemoteService - restarts after closing the launching Activity

I'm blocked with this for a few days and can't find the answer on this.
I start a remote service from an Activity. After starting the service, I close the launching Activity.
I close the main Activity from the task manager like this: home_btn long press and the list of opened app appears and then swipe left on the main Activity.
The thing that happens is that my service gets restarted! even thought it is a remote service, that has it's own process, doesn't depend on the launching activity!
All the internal variables are going to be reset and I don't want that.
-I don't want to use useForeground() method because I don't want my service to be visible in Notification
I currently start a Remote Service like this and the service starts(I can see it in the menu Settings->Apps-> tab Running):
btnStartSrv.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
startService(new Intent("com.example.servicerst_tst.RemoteService"));
}
});
android manifest xml looks like this:
<service android:name="com.example.servicerst_tst.RemoteService"
android:process=":serviceTST" >
<intent-filter>
<action android:name="com.example.servicerst_tst.RemoteService" >
</action>
</intent-filter>
</service>
the service class:
public class RemoteService extends Service{
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
I'm seeing the service restarting or reseting .. in the DDMS.
When closing main Activity the service disappears from the list in the DDMS and the gets started by itself in about 2 seconds. This can be visible in the service also. If you place some internal variables that get change during the life of the service. They will get reset, like the the service is restarting itself after closing the main Activity.
I just want my service not to reset, restart when I'm closing the main launcher Activity.
If the user closes the launcher Activity, from task manager or by his mistake, I want the service to run in background.
Am I doing something wrong here or missing something from my code to prevent restarting?
Why is reseting the service?
From Android Developers - Services : "if the service is declared to run in the foreground (discussed later), then it will almost never be killed. Otherwise, if the service was started and is long-running, then the system will lower its position in the list of background tasks over time and the service will become highly susceptible to killing—if your service is started, then you must design it to gracefully handle restarts by the system".
Declaring your service to run in the foreground has specific requirements: "A foreground service must provide a notification for the status bar, which is placed under the "Ongoing" heading, which means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground." and "To request that your service run in the foreground, call startForeground()." I know you said you don't want it to be a foreground service, but you have to live with the parameters Android sets out for you.
Solved problem with restarting service when launching Activity closes!
You should use startForeground() to not have this issue.
So startForeground() solved the restarting problem when closing launching Activity.
I've made also the service, restarting reliable.
Still I have a question..how the services ... like facebook and other big services run in background without any startForeground() implemented.
Also they are not killed by the system and they run in background forever without any startForeground() implementation. they live forever in background. For sure is somehow possible.
Does anyone know how?
How to avoid notification but still implementing the startForeground() method:
This is done By implementing the notification without
.setSmallIcon(R.drawable.ic_launcher)
for other details see
How to correctly handle startForegrounds two notifications

IntentService not firing

My application synchronizes data with a remote database via web service calls. I make these calls in an IntentService so they can run in the background (I call it SyncService).
The code to launch my IntentService looks like so:
Intent intent = new Intent();
intent.setClass(appContext, SyncService.class);
// place additional values in intent
intent.putExtra("data_type", SyncService.ITEM_TRACKING);
intent.putExtra("user_id", intUserId);
// call SyncService
appContext.startService(intent);
This, normally, looks great. However, one of my friends, who is also a user of my app, often tells me his data doesn't sync and get displayed on our website. His device happened to be displaying the symptoms while I was around. I plugged his device into my computer and here is what I found:
The code to launch SyncService (ie: the code above) was hit.
I had a breakpoint inside the onHandleIntent method of my IntentService and it never gets hit.
I checked his device's list of running services and SyncService was there and running. Interestingly, it had been running for about 20 minutes. I was under the impression that IntentService killed itself when it was all out of Intents to process.
I force stopped the SyncService (not the app) and, all of the sudden, onHandleIntent started getting hit over and over. It was like all the Intents were queued up somewhere on the device and were just now getting thrown at the SyncService.
Does anyone have any ideas as to what may be the problem? Do you think it's an issue with my app? With Android?
Again, I am handing a message to Android saying, "Start this IntentService or send the message to the already running IntentService." At that point, I have no control. The message never gets to the IntentService. Once I force quit the app, the messages get sent to the IntentService and it does its job.
UPDATE: I think this code is fine, but I'll put it up since a lot of you may want to see it.
Every Intent that comes in to the IntentService has an Extra denoting what "type" of call is to me made (ie: do I call this web service or that web service, etc). When an Intent comes in to the IntentService, I check the "type" and, if there is already an Intent in the queue for that type, I add an Extra to it called "skip" so, when it is reached, I don't execute the search (basically the IntentService can build up lots of Intents and it makes no sense to call this web service when this webservice was called 20 seconds ago). It basically protects the app from spamming the website.
It is important to note that none of this code is hit anyway (once the problem starts occurring). onStartCommand does not get called until the app is killed
#Override
public int onStartCommand (Intent intent, int flags, int startId) {
// here be dragons
// overriding this method and adding your own code is dangerous. i've wrapped
// my code in a try/catch because it is essential that the super method be called
// every time this method is entered. any errors in my code should not prevent this
// or the app will explode.
try {
if (flags == 0 && intent != null && intent.hasExtra("data_type")) {
Integer intDataType = intent.getExtras().getInt("data_type");
if (!mCurrentTypes.containsKey(intDataType)
|| !mCurrentTypes.get(intDataType)) {
mCurrentTypes.put(intDataType, true); // put this type in the list and move on
}
else {
intent.putExtra("skip", true); // mark this Intent to be skipped
}
}
}
catch (Exception e) {
// Log.e("Error onStartCommand", "error: " + e);
}
return super.onStartCommand(intent, flags, startId);
}
private void processIntent(Intent intent) {
// do stuff if no "skip" Extra
mCurrentTypes.put(intDataType, false);
}
There is definitly something that keeps your service running on your friend's device. If so all subsequent call to this intent service are queued until the current one finishes. If it doesn't finish then you will get what you have : next services won't start.
You should double check that :
you give proper timeouts to nework operations
you give proper timeouts to nework connections operations
there is no race condition between threads.
you log any exception that can occur inside the service, you don't wanna loose that kind of information.
Afterwards, if you think everything is green : just log what the service does and use some bug reporting mechanism to get it automatically sent from your friends device. A simple solution could be to use bugsense or equivalent.
Next, put in place some kind of watchdog : a thread that will go on running until your service stops (you just tell your thread to stop when service is stopped). The thread will have to stop your service after some time limit has been passed.
This watchdog thread could be put inside the service itself, or outside, although this may be more complex to put in place.
This answer suggests a solution that worked for me in similar situations. It doesn't fix your current code but suggests another, perhaps simpler (and easier to debug) option:
Add a BroadcastReceiver to your calling Activity that listens for SUCCESS Intents from the IntentService.
In your calling Activity, include the logic for when to start the IntentService (and don't include it in the IntentService). The logic is:
Call startService() and set a flag in the calling Activity to CANNOT_CALL.
If the Activity's BroadcastReceiver has not received a SUCCESS broadcast from the IntentService, then startService() can not be called again.
When the Activity does receive a SUCCESS intent, set the flag to CAN_CALL, and startService() can be called when the timer hits again.
In your IntentService, write your onStartCommand() like so:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
In you IntentService, when you've received, parsed and stores the web service response, call sendBroadcast() with an Intent with custom action SUCCESS.
This logic is just an outline and has to be fine-tuned for error messages from the web service that have to be broadcast from IntentService to the listening Activity.
Hope this helps.
It seems to me that setting a set of flags to your Intent may solve the problem.
Intent intent = new Intent();
intent.setClass(appContext, SyncService.class);
// This way
intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK|Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
You can make your Service start as fresh using the above flag in a fresh task.
One more comment. It's not an answer for your question. However, it may affect overall behavior of a service.
You do following:
return super.onStartCommand(intent, flags, startId);
Internally Service.onStartCommand() looks like following
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
mStartCompatibility is false if your app target SDK API 7 or later (which is most likely a case).
So, as result your service will be started as START_STICKY.
Here is piece from documentation:
For started services, there are two additional major modes of operation they can decide to run in, depending on the value they return from onStartCommand(): START_STICKY is used for services that are explicitly started and stopped as needed, while START_NOT_STICKY or START_REDELIVER_INTENT are used for services that should only remain running while processing any commands sent to them. See the linked documentation for more detail on the semantics.
Base on what you have described, I recommend to replace "return super.onStartCommand(intent, flags, startId);" to "return START_NOT_STICKY;"

GPS Tracking App (strategy)

I am currently working on a GPS tracking App (only the distance, not storing each value or displaying in a MapView) for a car-drivers logbook.
Cause of a docked phone, I do not care about power consumption.
My implementation so far is an activity that calls a GPS-Helper class which is getting the long/lat.
The activity itself calculates the driven distance, displays it for the user and starts a notification bar that also displays the distance. To keep the activity active and not killed by the OS, I am using a PARTIAL WakeLock for the activity.
My problem is that this is not working correctly, cause my App seems to be killed by the OS inspite of the WakeLock. I think that it is killed, cause when I click on the notification bar item (after 15-30 min. for example) to see the driven distance in my running activity, the activity is shown as it is to start a new GPS-track instead of displaying the driven distance from the former started track.
The WAKELOCK Permission is correctly set in the Manifest.
My question now is to get know if this costruct could be working or is there a better way to do this?
Your problem may be with the Intent you are launching when you click on the notification. This intent is most likely thinking that you want to launch a brand new Activity rather than returning the old activity to the foreground.
This link may help you to do what you want:
How to bring Android existing activity to front via notification
You should use a service which calls startForground, which requires a notification. This notification will be your entry point back into the app. The service can run in the background and log coordinates without depending on the life cycle of your Activity.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent.getAction().equals(DRIVELOG_ACTION_STOPLOGGING)){ handleStopLoggingCommand(intent.getBooleanExtra(SAVE_LOG,false));
}
else if(intent.getAction().equals(DRIVELOG_ACTION_STARTLOGGING)){
handleStartLoggingCommand();
}
return START_STICKY;
}
private void handleStartLoggingCommand() {
startForeground(DriveLoggerNotification.notificationId,DriveLoggerNotification.createInDriveLogNotification(this,driveLogLiveData));
if(googleApiClient.isConnected()){
startMonitoringLocation();
}else {
googleApiClient.connect();
}
}
This code is from my GpsLoggingService

Categories

Resources