16

I am trying to spawn a service that stays alive all the time, even if the user closes the application. According to these threads

Keep location service alive when the app is closed

Android Service Stops When App Is Closed

Android: keep Service running when app is killed

this can be accomplished with IntentServices or Service.START_STICKY

Yet, I tried both types of services without success. In other words, my services get killed when the app is closed by the user. Can someone point out if this is can be done and how? Here is what I have tried without success:

With IntentService:

public class MyIntentService extends IntentService {
    private final int mPollingTimeMS = 500;
    private int mInitializationPollingCount = 0;
    private Thread mPollThread;
    public MyIntentService() {
        super("MyIntentService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        mPollThread = new Thread() {
            public void run() {
                while (true) {
                    try {
                        Log.e(Constants.Engine.LOGGER_TAG_DEV,
                                "SDK Service Running: " +
                                        mInitializationPollingCount * mPollingTimeMS +
                                        "ms have elapsed");
                        mInitializationPollingCount++;
                        sleep(mPollingTimeMS);

                    } catch (Exception e) {
                        StackTraceElement trace = new Exception().getStackTrace()[0];
                        Logger.e(Constants.Engine.LOGGER_TAG_APP, "[Exception:" + e.toString() + "]" +
                                trace.getClassName() + "->" + trace.getMethodName() + ":" + trace.getLineNumber());
                    }
                }
            }
        };
        mPollThread.start();
    }
}

and with Services:

public class MyService extends Service {
    public MyService() {
    }
    private final int mPollingTimeMS = 500;
    private int mInitializationPollingCount = 0;
    private Thread mPollThread;
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mPollThread = new Thread() {
            public void run() {
                while (true) {
                    try {
                        Log.e(Constants.Engine.LOGGER_TAG_DEV,
                                "SDK Service Running: " +
                                        mInitializationPollingCount * mPollingTimeMS +
                                        "ms have elapsed");
                        mInitializationPollingCount++;
                        sleep(mPollingTimeMS);

                    } catch (Exception e) {
                        StackTraceElement trace = new Exception().getStackTrace()[0];
                        Logger.e(Constants.Engine.LOGGER_TAG_APP, "[Exception:" + e.toString() + "]" +
                                trace.getClassName() + "->" + trace.getMethodName() + ":" + trace.getLineNumber());
                    }
                }
            }
        };
        mPollThread.start();
        return Service.START_STICKY;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // I tried to return null here, but this
        // service gets killed no matter what.
        return null;
    }
}

and here is the manifest:

    <service
        android:name=".mycompany.MyService"
        android:enabled="true"
        android:exported="true"
        android:process=":process1">
    </service>
    <service
        android:name=".mycompany.MyIntentService"
        android:process=":process2"
        android:exported="false">
    </service>

I shall added that I am closing the test app not with a close button, but using the Android OS app manager. See picture below

enter image description here

Lastly, the driver activity (not much there)

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent1 = new Intent(getBaseContext(), MyService.class);
        startService(intent1);
        Intent intent2 = new Intent(getBaseContext(), MyIntentService.class);
        startService(intent2);

    }
}

I also try to add a notification and make it a foreground service but still the same thing. The moment I close the app, everything gets killed. This is what I added:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    showNotification();
...etc..

private void showNotification() {
    Intent notificationIntent = new Intent(this, MainActivity.class);
    notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
            notificationIntent, 0);
    int iconId = R.mipmap.ic_launcher;
    int uniqueCode = new Random().nextInt(Integer.MAX_VALUE);
    Notification notification = new NotificationCompat.Builder(this)
            .setSmallIcon(iconId)
            .setContentText("Context Text")
            .setContentIntent(pendingIntent).build();
    startForeground(uniqueCode, notification);
}
Community
  • 1
  • 1
gmmo
  • 2,577
  • 3
  • 30
  • 56
  • Sometimes if you're low on memory, the service will stop irrespective. Try making it as a foreground service if you need it persistent, you can do that by making a notification and calling the service. Lots of documentation around. – Anindya Dutta Feb 09 '17 at 02:10
  • @AnindyaDutta I doubt this is the problem. The phone is running only one app, and it always shuts down the services. – gmmo Feb 09 '17 at 02:27
  • 1
    you do not want an intentservice for this – Tim Feb 09 '17 at 23:32

5 Answers5

21

Here is an example of foreground service that I use and that works, it remains active when the app is closed. Of course, it also must be started, and for that task the app must be running at a first glance, or a receiver of a boot event must be set, but this is another story.

public class MyService extends Service {
static final int NOTIFICATION_ID = 543;

public static boolean isServiceRunning = false;

@Override
public void onCreate() {
    super.onCreate();
    startServiceWithNotification();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (intent != null && intent.getAction().equals(C.ACTION_START_SERVICE)) {
        startServiceWithNotification();
    }
    else stopMyService();
    return START_STICKY;
}

// In case the service is deleted or crashes some how
@Override
public void onDestroy() {
    isServiceRunning = false;
    super.onDestroy();
}

@Override
public IBinder onBind(Intent intent) {
    // Used only in case of bound services.
    return null;
}


void startServiceWithNotification() {
    if (isServiceRunning) return;
    isServiceRunning = true;

    Intent notificationIntent = new Intent(getApplicationContext(), MyActivity.class);
    notificationIntent.setAction(C.ACTION_MAIN);  // A string containing the action name
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    PendingIntent contentPendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

    Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.my_icon);

    Notification notification = new NotificationCompat.Builder(this)
            .setContentTitle(getResources().getString(R.string.app_name))
            .setTicker(getResources().getString(R.string.app_name))
            .setContentText(getResources().getString(R.string.my_string))
            .setSmallIcon(R.drawable.my_icon)
            .setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
            .setContentIntent(contentPendingIntent)
            .setOngoing(true)
//                .setDeleteIntent(contentPendingIntent)  // if needed
            .build();
    notification.flags = notification.flags | Notification.FLAG_NO_CLEAR;     // NO_CLEAR makes the notification stay when the user performs a "delete all" command
    startForeground(NOTIFICATION_ID, notification);
}

void stopMyService() {
    stopForeground(true);
    stopSelf();
    isServiceRunning = false;
}
}

Then I run it with

    Intent startIntent = new Intent(getApplicationContext(), MyService.class);
    startIntent.setAction(C.ACTION_START_SERVICE);
    startService(startIntent);

Please note the two constants used as Actions, these are Strings that must start with the package name.

Beppi's
  • 2,089
  • 1
  • 21
  • 38
  • Is it possible to have the foreground service without push notification icon? It does not look like so, but just wondering. – gmmo Feb 10 '17 at 01:59
  • 1
    No. The reason for the icon is because, for Android policies, the user must be in control of the app and must be able to kill it. – Beppi's Feb 10 '17 at 02:48
  • 13
    What is "C" in C.ACTION_START_SERVICE – Viks Apr 01 '18 at 03:52
  • Please tell me what is C.ACTION_START_SERVICE!! Tried adding package name.failed!! – Heena Jan 04 '19 at 07:45
  • @Heena C.ACTION_START_SERVICE is just a constant referred to his class C. You can name it whatever you like. – Bibin Johny Jan 20 '19 at 07:49
  • It works on my Virtual Device, but not on my phone. Any idea why? Oh, i figure it out, with huawei phone you must set the app as protected :O – slaviboy Feb 16 '19 at 08:40
  • 2
    Android 8.1: it doesn't work. Maybe problem is in my phone (SMJ610). It doesn't work as expected. When I launch application it starts sequence of commands that should create the service, and run the command. I see the notification in my notification bar and even cannot remove it (it's good). But once I close the app the notification is being removed and music stops (I'm making an audio player). – alexanderktx Apr 15 '19 at 15:40
  • @VikashParajuli - Most likey C here is simply a Constant class holding all constants, Because setAction can not take anything other than a String. – Alex May 13 '20 at 13:03
6

IntentService

Using IntentService is probably not the best approach. By default IntentService stops itself after onHandleIntent(Intent) returns and there's no work left to do (i.e. the request queue is empty). This is explained in the official docs of IntentService:

When all requests have been handled, the IntentService stops itself, so you should not call stopSelf().

In your case, onHandleIntent(Intent) creates a thread but returns right away, which makes it stop by itself.

Service + startForeground()

Using a regular Service in foreground mode should work as long as you keep that service running on a separate process. For that, you need:

  1. Make the onStartCommand() return START_STICKY.
  2. Call the method to show the notification right in onCreate().
  3. Run the service in a separate process (using android:process=":something").

Based on the post, it seems that you've tried some of these steps in isolation but never tried all of them at the same time.

Mike Laren
  • 8,028
  • 17
  • 51
  • 70
  • run service in separate process....@MikeLaren, i dont get it ....? – gumuruh Jan 11 '21 at 18:25
  • By default, Services on Android run in the same (OS level) process as the rest of the UI. However, you can change this behavior using the "android:process" attribute in the declaration of the service in AndroidManifest.xml. This has some advantages but also has disadvantages. Check the documentation for the android:process attribute and questions such as https://stackoverflow.com/questions/7142921 for a detailed explanation about the pros and cons of doing this. – Mike Laren Jan 12 '21 at 00:46
  • okay @MikeLaren, thanks for the info. Anyway, that seems doesn't give any effect if the activity is closed from the task manager. Every services it has become closed too... – gumuruh Jan 12 '21 at 14:59
2

If none of the answers above are working, maybe it is a manufacturer specific issue. Some MI phones, for instance, kill the foreground service when the user kill the app via task manager.

I recommend you to test the app on a virtual device, so you can check if it is or isn't this kind of issue.

Hope it helps!

Geraldo Neto
  • 3,670
  • 1
  • 30
  • 33
0

You can simply call your service in your onStop() method inside your activity. Even when user stops the app the service will still be running.

Gordon developer
  • 387
  • 3
  • 13
0

Try the answers for this similar question: Bad notification for startForeground in Android app

sandeepani
  • 353
  • 3
  • 12