Android Service Stops When App Is Closed
Asked Answered
L

14

90

I am starting a service from my main Android activity as follows:

final Context context = base.getApplicationContext();
final Intent intent = new Intent(context, MyService.class);
startService(intent);

When I close the activity page by swiping it out from the recent apps list, the service stops running and restarts after some time. I can't use persistent services with notifications because of my app requirements. How can I make the service NOT restart or shutdown and just keep on running on app exit?

Liederman answered 20/5, 2013 at 13:49 Comment(4)
possible duplicate of The process of the service is killed after the application is removed from the application trayLyonnais
@kiran The problem I'm facing is that the service gets restarted when the activity closes. I'm looking for a way to keep the service running at all times (without a restart on activity finished).Liederman
I feel we cannot achieve that. On low resources, your service is going to be killed. The best we could hope is a restart. And on 4.4+, swipe kill will not even restart the service. Please read this threadLyonnais
Think hard about whether you really need your service running literally all the time: this is bad for power and memory consumption.Mcvey
H
53

I'm in the same situation, so far I learned that when the App is closed the Service gets closed as well, because they are in the same main-thread (aka process), so the service should be on another main-thread in order for it NOT to be closed, look into that and look into keeping the service alive with alarm-manager, here an example http://www.vogella.com/articles/AndroidServices/article.html this way your service won't be shown in notification.

Lastly, after all the research I've done I'm coming to realize that the best choice for a long running service is startForeground() (which shows notification), because it is made for that and the system actually deals with your service well.

Note that in case of a VpnService, startForeground is not required, because there is a built-in notification for VPNs.

Update: said built-in notification got removed by google (now VpnService needs startForeground as well).

Hays answered 22/6, 2013 at 23:7 Comment(5)
@Liederman I have this exact problem. However, my service IS a foreground service and it still gets killed when my activity is closed. I changed my intent initialization argument from the context getApplicationContext() to getBaseContext() and it solved the issue.Fineable
can I use getBaseContext() in pendingIntent?Orthopedist
instead of using notificationManager.notify(intent.getIntExtra("notification_Id", 0), builder.build()); should i use startForeground(intent.getIntExtra("notification_Id, 0), builder.build()); ? I'm using NotificationCompat.BuilderOrthopedist
startForeground() need api 26 is there any soluction?Pitts
@Pitts Yes, older android versions don't kill service, hence call startForeground(...) method for new API only (check version with if-condition and use start(...) instead).Always
C
13

make you service like this in your Mainifest

 <service
            android:name=".sys.service.youservice"
            android:exported="true"
        android:process=":ServiceProcess" />

then your service will run on other process named ServiceProcess


if you want make your service never die :

  1. onStartCommand() return START_STICKY

  2. onDestroy() -> startself

  3. create a Deamon service

  4. jin -> create a Native Deamon process, you can find some open-source projects on github

  5. startForeground() , there is a way to startForeground without Notification ,google it

Coastline answered 21/7, 2016 at 6:50 Comment(2)
Pretty sure starting itself in onDestroy would be considered fighting the android system, which is bad practice.Haakon
Daemon, you meanPrelate
C
13

Services are quite complicated sometimes.

When you start a service from an activity (or your process), the service is essentially on the same process.

quoting from the developer notes

Most confusion about the Service class actually revolves around what it is not:

A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.

A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).

So, what this means is, if the user swipes the app away from the recent tasks it will delete your process(this includes all your activities etc). Now, lets take three scenarios.

First where the service does not have a foreground notification.

In this case your process is killed along with your service.

Second where the service has a foreground notification

In this case the service is not killed and neither is the process

Third scenario If the service does not have a foreground notification, it can still keep running if the app is closed. We can do this by making the service run in a different process. (However, I've heard some people say that it may not work. left to you to try it out yourself)

you can create a service in a separate process by including the below attribute in your manifest.

android:process=":yourService"

or

android:process="yourService" process name must begin with lower case.

quoting from developer notes

If the name assigned to this attribute begins with a colon (':'), a new process, private to the application, is created when it's needed and the service runs in that process. If the process name begins with a lowercase character, the service will run in a global process of that name, provided that it has permission to do so. This allows components in different applications to share a process, reducing resource usage.

this is what I have gathered, if anyone is an expert, please do correct me if I'm wrong :)

Cribwork answered 31/8, 2017 at 19:10 Comment(0)
M
12

This may help you. I may be mistaken but it seems to me that this is related with returning START_STICKY in your onStartCommand() method. You can avoid the service from being called again by returning START_NOT_STICKY instead.

Megavolt answered 20/5, 2013 at 13:55 Comment(2)
Actually the service stops running when I exit or close the app (and then service restarts). I don't want the service to pause/stop when I exit/close the app; I want it to keep on running. I believe the solution has something to do with running the service on a separate process but I'm not really sure.Liederman
Working fine artex, ThanksCrucifer
C
6

The Main problem is in unable to start the service when app closed, android OS(In Some OS) will kill the service for Resource Optimization, If you are not able to restart the service then call a alarm manger to start the receiver like this,Here is the entire code, This code will keep alive ur service.

Manifest is,

         <service
            android:name=".BackgroundService"
            android:description="@string/app_name"
            android:enabled="true"
            android:label="Notification" />
        <receiver android:name="AlarmReceiver">
            <intent-filter>
                <action android:name="REFRESH_THIS" />
            </intent-filter>
        </receiver>

IN Main Activty start alarm manger in this way,

String alarm = Context.ALARM_SERVICE;
        AlarmManager am = (AlarmManager) getSystemService(alarm);

        Intent intent = new Intent("REFRESH_THIS");
        PendingIntent pi = PendingIntent.getBroadcast(this, 123456789, intent, 0);

        int type = AlarmManager.RTC_WAKEUP;
        long interval = 1000 * 50;

        am.setInexactRepeating(type, System.currentTimeMillis(), interval, pi);

this will call reciver and reciver is,

public class AlarmReceiver extends BroadcastReceiver {
    Context context;

    @Override
    public void onReceive(Context context, Intent intent) {
        this.context = context;

        System.out.println("Alarma Reciver Called");

        if (isMyServiceRunning(this.context, BackgroundService.class)) {
            System.out.println("alredy running no need to start again");
        } else {
            Intent background = new Intent(context, BackgroundService.class);
            context.startService(background);
        }
    }

    public static boolean isMyServiceRunning(Context context, Class<?> serviceClass) {
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

        if (services != null) {
            for (int i = 0; i < services.size(); i++) {
                if ((serviceClass.getName()).equals(services.get(i).service.getClassName()) && services.get(i).pid != 0) {
                    return true;
                }
            }
        }
        return false;
    }
}

And this Alaram reciver calls once when android app is opened and when app is closed.SO the service is like this,

public class BackgroundService extends Service {
    private String LOG_TAG = null;

    @Override
    public void onCreate() {
        super.onCreate();
        LOG_TAG = "app_name";
        Log.i(LOG_TAG, "service created");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(LOG_TAG, "In onStartCommand");
        //ur actual code
        return START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // Wont be called as service is not bound
        Log.i(LOG_TAG, "In onBind");
        return null;
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Log.i(LOG_TAG, "In onTaskRemoved");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(LOG_TAG, "In onDestroyed");
    }
}
Corvette answered 17/1, 2017 at 7:10 Comment(0)
A
5

From Android O, you cant use the services for the long running background operations due to this, https://developer.android.com/about/versions/oreo/background . Jobservice will be the better option with Jobscheduler implementation.

Annabelle answered 7/2, 2019 at 6:52 Comment(1)
What is Jobservice?Nesselrode
N
1

try this, it will keep the service running in the background.

BackServices.class

public class BackServices extends Service{

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
      // Let it continue running until it is stopped.
      Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
      return START_STICKY;
   }
   @Override
   public void onDestroy() {
      super.onDestroy();
      Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
   }
}

in your MainActivity onCreate drop this line of code

startService(new Intent(getBaseContext(), BackServices.class));

Now the service will stay running in background.

Nitrification answered 3/12, 2014 at 12:1 Comment(1)
The problem is stil there: when I kill the app from the recents menu the service gets restarted (onStartCommand gets called again). The only thing that helped me was making it a foreground service.Liederman
G
1

Using the same process for the service and the activity and START_STICKY or START_REDELIVER_INTENT in the service is the only way to be able to restart the service when the application restarts, which happens when the user closes the application for example, but also when the system decides to close it for optimisations reasons. You CAN NOT have a service that will run permanently without any interruption. This is by design, smartphones are not made to run continuous processes for long period of time. This is due to the fact that battery life is the highest priority. You need to design your service so it handles being stopped at any point.

Grating answered 6/8, 2017 at 9:57 Comment(0)
I
1

You must add this code in your Service class so that it handles the case when your process is being killed

 @Override
    public void onTaskRemoved(Intent rootIntent) {
        Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
        restartServiceIntent.setPackage(getPackageName());

        PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
        AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        alarmService.set(
                AlarmManager.ELAPSED_REALTIME,
                SystemClock.elapsedRealtime() + 1000,
                restartServicePendingIntent);

        super.onTaskRemoved(rootIntent);
    }
Irresponsive answered 3/10, 2017 at 7:45 Comment(0)
P
0

Why not use an IntentService?

IntentService opens a new Thread apart from the main Thread and works there, that way closing the app wont effect it

Be advised that IntentService runs the onHandleIntent() and when its done the service closes, see if it fits your needs. http://developer.android.com/reference/android/app/IntentService.html

Pivotal answered 31/5, 2015 at 9:2 Comment(1)
Actually my requirement was to have an always running background service. Starting the service as a Foreground Service solved it for me.Liederman
Q
0

Best solution is to use the sync Adapter in android to start the service. Create a Sync Adapter and call start service their.. inside onPerformSync method. to create sync Account please refer this link https://developer.android.com/training/sync-adapters/index.html

Why SyncAdapter? Ans: Because earlier you used to start the service using your App context. so whenever your app process get killed (When u remove it from task manager or OS kill it because of lack of resources ) at that time your service will also be removed. SyncAdapter will not work in application thread.. so if u call inside it.. service will no longer be removed.. unless u write code to remove it.

Quadrifid answered 6/7, 2017 at 8:1 Comment(0)
Q
0
<service android:name=".Service2"
            android:process="@string/app_name"
            android:exported="true"
            android:isolatedProcess="true"
            />

Declare this in your manifest. Give a custom name to your process and make that process isolated and exported .

Quadrifid answered 7/7, 2017 at 10:37 Comment(0)
G
0

Running an intent service will be easier. Service in creating a thread in the application but it's still in the application.

Gean answered 14/11, 2017 at 22:52 Comment(0)
S
-6

Just override onDestroy method in your first visible activity like after splash you have home page and while redirecting from splash to home page you have already finish splash. so put on destroy in home page. and stop service in that method.

Shaughn answered 18/1, 2016 at 10:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.