Cannot Keep Android Service Alive After App Is Closed

Cannot keep android service alive after app is closed

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.

Android Service not staying alive after app closes

If you actively close the app (by closing it from the Android activity list), Android will most likely kill your service. You can see that in your apps Logcat. The only real way around that is a foreground service.

Furthermore, onBind will not be called every time you bind to the service. From the Android documentation:

You can connect multiple clients to a service simultaneously. However, the system caches the IBinder service communication channel. In other words, the system calls the service's onBind() method to generate the IBinder only when the first client binds. The system then delivers that same IBinder to all additional clients that bind to that same service, without calling onBind() again.

Secondly, just that onStartCommand is called does not mean the service is recreated. It can be called multiple times during the service life cycle. For instance, each time startService is called, onStartCommand is executed, but the service is not necessarily recreated.

Also, it looks like you do not un-bind the service when closing the activity. That makes your activity leak the ServiceConnection and your app crash. It would explain why you see the service re-created every time you close and re-start the app.

Try adding an unbind in your activity's onPause method:

@Override
void onPause() {
super.onPause()
unbindService(this.serviceConnectino)
}

A working configuration could look like below. It implements incrementing the counter using a dedicated service function, rather than onBind:

MyBoundService.kt

package com.test

import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log

class MyBoundService : Service() {

abstract class MyBinder: Binder() {
abstract fun getService(): MyBoundService
}

val iBinder: MyBinder = object: MyBinder() {
override fun getService(): MyBoundService {
return this@MyBoundService
}
}

private var counter = 0

fun increment() {
counter ++
Log.i("MyBoundService", "Counter: ${counter}")
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.i("MyBoundService", "startCommand");
return super.onStartCommand(intent, flags, startId)
}

override fun onBind(p0: Intent?): IBinder? {
counter++
Log.i("MyBoundService", "Bound: ${counter}")
return iBinder
}

override fun onUnbind(intent: Intent?): Boolean {
Log.i("MyBoundService", "Unbound")
return super.onUnbind(intent)
}
}

MainActivity.kt

package com.test

import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
import android.content.ComponentName
import android.content.Context
import android.content.ServiceConnection
import android.os.IBinder
import android.util.Log
import com.test.MyBoundService

class MainActivity : AppCompatActivity() {


private val serviceConnection: ServiceConnection = object: ServiceConnection {
override fun onServiceDisconnected(p0: ComponentName?) {
Log.i("MainActivity", "Service disconnected")
}

override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
Log.i("MainActivity", "Service connected")
p1?.let {
(p1 as MyBoundService.MyBinder).getService().increment()
}
}

}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

btn_create.setOnClickListener {
val i = Intent(this@MainActivity, MyBoundService::class.java)
startService(i)
}

btn_bind.setOnClickListener {
val i = Intent(this@MainActivity, MyBoundService::class.java)
bindService(i, serviceConnection, Context.BIND_AUTO_CREATE)
}
}

override fun onPause() {
super.onPause()
unbindService(serviceConnection)
}
}

Android Service Stops When App Is Closed

I'm in the same situation, so far I learned when the app is closed the service get closed also because they are in a one thread, so the service should be on another thread in order fot 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(), because it is made for that and the system actually deals with your service well.

keeping background service alive after user exit app

According to the Android documentation you can achieve this behavior by using the attribute:

 android:isolatedProcess="true"

By the way, I know that it's not answering the question but it might help some people as well - lately, I found out about a great third-party lib that Evernote developers have created. Its name is Android-Job and its aim is to create jobs that run on different processes and can become active again even after a device reboot, it's amazing.



Related Topics



Leave a reply



Submit