I noticed that Service.START_STICKY doesn't work and when I tokk a closer look, I saw the onCreate() is running but onStartCommand is not called.
Any ideas why?
#Override
public void onCreate() {
mGlobalData = GlobalData.getInstance();
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (mTimer == null)
mTimer = new Timer();
Log.e(TAG, "onCreate()");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
int t = START_STICKY;
Log.e(TAG, "call me redundant BABY! onStartCommand service");
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return t;
}
If you have the same situation I had, my Service starts up and runs just fine (onCreate() and onServiceConnected() are both invoked) but onStartCommand(Intent,int) was never called. I found it's because the system started my Service instead of me explicitly starting the Service in code. According to the docs:
[onStartCommand(Intent,int) is] called by the system every time a client explicitly starts the service by calling startService(Intent)
So I had to call startService(new Intent(context, MyService.class)) explicitly in code to get onStartCommand(Intent,int) to trigger. Note that doing this will not restart the Service created by the system and it won't create a new instance of that Service either.
Try to insert the line android.os.Debug.waitForDebugger(); at the end of onCreate(). The debugger didn't reach onStartCommand()'s breakpoints for me until I did this.
Related
I've created a service that its job is to clear the notifications when the app is closed by the user. Everything works perfectly well but sometimes when the application is in the background for more than 1 minute the service is killed (which means that the notifications are not cancelled).
Why is this happening? I thought that the only way that you can stop a service is by using either stopSelf() or stopService().
public class OnClearFromRecentService extends Service {
private static final String TAG = "onClearFromRecentServic";
private NotificationManagerCompat mNotificationManagerCompat;
#Override
public void onCreate() {
super.onCreate();
mNotificationManagerCompat = NotificationManagerCompat.from(getApplicationContext());
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "Service Started");
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Service Destroyed");
}
#Override
public void onTaskRemoved(Intent rootIntent) {
//Put code here which will be executed when app is closed from user.
Log.d(TAG, "onTaskRemoved was executed ");
if (mNotificationManagerCompat != null) {
mNotificationManagerCompat.cancelAll();
} else {
Log.d(TAG, "onTaskRemoved: mNotifManager is null!");
}
stopSelf();
}
}
I start the service from the splash screen Activity like this: startService(new Intent(this, OnClearFromRecentService.class));
Also here are some Log messages:
Try returning START_STICKY form onStartCommand.
Then system will try to recreate.
check this official doc.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "Service Started");
return START_NOT_STICKY;
}
Also you can try returing START_REDELIVER_INTENT,if you also want Intent to be re-delivered.
START_REDELIVER_INTENT
Constant to return from onStartCommand(Intent, int, int): if this
service's process is killed while it is started (after returning from
onStartCommand(Intent, int, int)), then it will be scheduled for a
restart and the last delivered Intent re-delivered to it again via
onStartCommand(Intent, int, int).
From docs.
I found a solution with the help of #emandt.
I just added these lines of code in onStartCommand() :
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "Service Started");
Notification notification = new NotificationCompat.Builder(this, CHANNELID)
.setContentTitle("title")
.setContentText("text")
.setSmallIcon(R.drawable.baseline_pause_white_24)
.build();
startForeground(2001,notification);
return START_NOT_STICKY;
}
According to docs the startForeground method :
If your service is started then also make this service run in the foreground, supplying the ongoing notification to be shown to the user while in this state...By default started services are background, meaning that their process won't be given foreground CPU scheduling (unless something else in that process is foreground)
Also,
If your app targets API level 26 or higher, the system imposes restrictions on using or creating background services unless the app itself is in the foreground. If an app needs to create a foreground service, the app should call startForegroundService(). That method creates a background service, but the method signals to the system that the service will promote itself to the foreground. Once the service has been created, the service must call its startForeground() method within five seconds.
I started a foreground service with a notification id however when i try to call stopForeground(false) the service is getting restarted. But according to the android docs calling this method does not stop the service.
#Override
public void onCreate() {
LogHelper.d(TAG, "onCreate");
super.onCreate();
initMediaSeesion();
}
#Override
public int onStartCommand(Intent startIntent, int flags, int startId) {
LogHelper.d(TAG, "onStartCommand");
MediaButtonReceiver.handleIntent(mSession, startIntent);
return START_STICKY;
}
public void startNotification() {
if (!mStarted) {
Notification notification = createNotification();
if (notification != null) {
mService.startForeground(NOTIFICATION_ID, notification);
mStarted = true;
}
}
}
#Override
public void pause() {
LogHelper.d(TAG, "Calling stopForeground false");
giveUpAudioFocus();
mService.stopForeground(false);
}
Logs:
03-25 08:50:40.200 19564-19564/? D/MusicService: Calling stopForeground false
03-25 08:50:40.352 19564-19564/? D/MusicService: onCreate
03-25 08:50:40.475 19564-19564/? D/MusicService: onStartCommand
03-25 08:50:40.476 19564-19564/? D/MusicService: onStartCommand
Because you set START_STICKY when you stop the service it automatically restart.
This is what Android DOC says
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.
Try using stopSelf();
I'm trying to do a StartedService in android to send periodically the user location to a server.
Until this moment I managed to create the service and starting it from the 'parent ' application and I don't know how to keep it alive after the application was killed. From what I found on internet the 'StartCommandResult.Sticky' should restart the service if this one is killed but from some reason this is not restarted.
I overried the OnStartCommand:
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
locationTask = new Task(() =>
{
//stuff to do
});
locationTask.Start();
return StartCommandResult.Sticky;
}
And the service is started like this:
Intent intent = new Intent(this.Activity, Class.FromType(typeof(LocationService)));
this.Activity.StartService(intent);
Any suggestions what should I do in order to keep my service alive after the application was killed?
As observation I'm using xamarin to do it, but I won't mind an answer in android(java).
As stated in the official documentation:
A service is "started" when an application component (such as an
activity) starts it by calling startService(). Once started, a service
can run in the background indefinitely, even if the component that
started it is destroyed. Usually, a started service performs a
single operation and does not return a result to the caller. For
example, it might download or upload a file over the network. When the
operation is done, the service should stop itself.
So, starting the service like this
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
Will have your service running even while your app is destroyed.
Regarding Service.START_STICKY in the official documentation:
If the system kills the service after onStartCommand() returns,
recreate the service and call onStartCommand(), but do not redeliver
the last intent. Instead, the system calls onStartCommand() with a
null intent, unless there were pending intents to start the service,
in which case, those intents are delivered. This is suitable for media
players (or similar services) that are not executing commands, but
running indefinitely and waiting for a job.
This is how I do it but its in JAVA code.
in your service you should implement a LocalBinder, onStartCommand and onCreate methods.
public class LocalBinder extends Binder {
ServiceName getService() {
return ServiceName .this;
}
}
#Override
public void onCreate() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
return START_STICKY;
}
The onStartCommand should return START_STICKY;. And also, include this code on your Service:
#Override
public void onTaskRemoved(Intent rootIntent) {
// TODO Auto-generated method stub
Intent restartService = new Intent(getApplicationContext(),this.getClass());
restartService.setPackage(getPackageName());
PendingIntent restartServicePI = PendingIntent.getService(getApplicationContext(), 1, restartService, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() +1000, restartServicePI);
}
This will restart your Service on 1 second from the time you close it. Also, dont forget to add your service in your AndroidManifest.xml
<service android:name=".ServiceName"
android:exported="false"
android:stopWithTask="false" >
</service>
Override onStartCommand like this
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
For me, everything in the code was right but the problem was with the use of debugging while checking if the service was on. When I use a release version (or just dev version without connecting to the debug), the process is not killed and the service is running normally.
No idea why though. I am using Xamarin Studio 6.0.
On click of a button I want to start service using method startService(new Intent(currentActivity.this,MyService.class)) but if service is running I don't want to call this method to avoid run service that is already running.How this is possible.I am using both Intent service and Service in same project and want to apply same condition for both.
A service will only run once, so you can call startService(Intent) multiple times.
You will receive an onStartCommand() in the service. So keep that in mind.
Source:
Note that multiple calls to Context.startService() do not nest (though they do result in multiple corresponding calls to onStartCommand()), so no matter how many times it is started a service will be stopped once Context.stopService() or stopSelf() is called; however, services can use their stopSelf(int) method to ensure the service is not stopped until started intents have been processed.
At: http://developer.android.com/reference/android/app/Service.html on topic: Service Lifecycle
Use startService().
Start Service will call onStartCommand() If the Service isn't started yet it will Call onCreate(). Initialize your variables and/or start a Thread in onCreate().
Bind your service; when starting call:
Intent bindIntent = new Intent(this,ServiceTask.class);
startService(bindIntent);
bindService(bindIntent,mConnection,0);
Then to check if your service is working, use a method like:
public static boolean isServiceRunning(String serviceClassName){
final ActivityManager activityManager = (ActivityManager)Application.getContext().getSystemService(Context.ACTIVITY_SERVICE);
final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
for (RunningServiceInfo runningServiceInfo : services) {
if (runningServiceInfo.service.getClassName().equals(serviceClassName)){
return true;
}
}
return false;
}
Whenever we start any service from any activity , Android system calls the service's onStartCommand() method And If the service is not already running, the system first calls onCreate(), and then it calls onStartCommand().
So mean to say is that android service start's only once in its lifecycle and keep it running till stopped.if any other client want to start it again then only onStartCommand() method will invoked all the time.
So, for avoiding restarting a task again and again, You can use boolean values, that the task is already started or ongoing. Put the method both in oncreate and onstartCommand, and checked with the boolean:
boolean isTimerTaskRunning = false;
private boolean isServiceKeepRunning(){
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
return settings.getBoolean("silentModeKeepRunning", true);
}
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate: Called");
Log.i(TAG, "onCreate: keepRunning "+isServiceKeepRunning());
if(!isTimerTaskRunning) {
startTimerTask();
isTimerTaskRunning = true;
}
//startForeground(REQUEST_CODE /* ID of notification */, notificationbuilder().build());
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
localData = new LocalData(this);
// return super.onStartCommand(intent, flags, startId);
Log.i(TAG, "onStartCommand: Called");
Log.i(TAG, "onStartCommand: keepRunning "+isServiceKeepRunning());
Toast.makeText(this, "This is The Mode For Silent. ", Toast.LENGTH_LONG).show();
if(!isTimerTaskRunning) {
Log.i(TAG, "TimerTask was not Running - started from onStartCommand");
startTimerTask();
isTimerTaskRunning = true;
}else {
Log.i(TAG, "TimerTask was already Running - checked from onStartCommand");
}
//return START_REDELIVER_INTENT;
startForeground(REQUEST_CODE /* ID of notification */, notificationbuilder().build());
return START_STICKY;
}
I'm having a problem with my IntentService. Every time I start my service, the onDestroy() method is called as soon as the service becomes idle. I set up my service to run in the foreground, and despite this the service is still being killed right away. I have only one other activity in my application, and it is not calling stopService().
Reading the developer docs gives me the impression that calling startForeground() will allow your service to persist, even when idle, except when there is an very high demand for memory, or am I reading this wrong?
My code below:
public class FileMonitorService extends IntentService {
public int mNotifyId = 273;
public FileMonitorService(){
super("FileMonitorService");
}
#Override
protected void onHandleIntent(Intent arg0) {
}
#Override
public void onDestroy() {
Toast.makeText(this, getText(R.string.toast_service_stop), Toast.LENGTH_SHORT).show();
stopForeground(true);
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = new Notification(R.drawable.icon, getText(R.string.notification_short), System.currentTimeMillis());
notification.flags|=Notification.FLAG_NO_CLEAR;
Intent notificationIntent = new Intent(this, FileMonitorActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_short),getText(R.string.notification_long), pendingIntent);
startForeground(mNotifyId, notification);
Toast.makeText(this, getText(R.string.toast_service_start), Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent, flags, startId);
}
}
You need to look into using a regular Service instead of an IntentService. IntentService is designed to keep running while it has work to do. Once you've finished your onStartCommand method, it tries to stop.
See the docs:
Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
(Emphasis mine)