Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: keep Service running when app is killed

I want to keep a IntentService running in background even when the app is killed. And by "killed" I mean press home-button for a long time -> see all running apps -> swipe my app aside -> app killed OR press back-button for a long time -> app killed

My code goes as follows. In my MainActivity:

Intent intent = new Intent(this, MyService.class); this.startService(intent); 

In my MyService:

public class MyService extends IntentService {  @Override protected void onHandleIntent(Intent intent) {     System.out.println("MyService started");     run(); }  private void run() {     while (true){         System.out.println("MyService still running");         doSomething();         waitSomeTime();     } }  } 

I see that the service is running when the app is open. It's still running when I minimize the app via home-button. It's still running when I close the app via back-button. But it will stop if I kill it as mentioned above. How do I solve this?

like image 501
user2078872 Avatar asked May 29 '15 09:05

user2078872


People also ask

How do I keep the service running when an app is killed?

1)Keep it running in the foreground by calling the startForeground() method. Show activity on this post. You can use android:stopWithTask="false" in manifest as bellow, This means even if user kills app by removing it from tasklist, your service won't stop.

How do I keep my service alive Android?

But in order to keep a service alive like playing a song in a background. You'll need to supply a Notification to the method which is displayed in the Notifications Bar in the Ongoing section. In this way the app will keep alive in background without any interuption.

How do I run background services on Android?

This example demonstrates how do I run an android service always in background. Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project. Step 2 − Add the following code to res/layout/activity_main. xml.


2 Answers

All the answers seem correct so I'll go ahead and give a complete answer here.

Firstly, the easiest way to do what you are trying to do is launch a Broadcast in Android when the app is killed manually, and define a custom BroadcastReceiver to trigger a service restart following that.

Now lets jump into code.


Create your Service in YourService.java

Note the onCreate() method, where we are starting a foreground service differently for Build versions greater than Android Oreo. This because of the strict notification policies introduced recently where we have to define our own notification channel to display them correctly.

The this.sendBroadcast(broadcastIntent); in the onDestroy() method is the statement which asynchronously sends a broadcast with the action name "restartservice". We'll be using this later as a trigger to restart our service.

Here we have defined a simple Timer task, which prints a counter value every 1 second in the Log while incrementing itself every time it prints.

public class YourService extends Service { public int counter=0;      @Override     public void onCreate() {         super.onCreate();         if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)             startMyOwnForeground();         else             startForeground(1, new Notification());     }      @RequiresApi(Build.VERSION_CODES.O)     private void startMyOwnForeground()     {         String NOTIFICATION_CHANNEL_ID = "example.permanence";         String channelName = "Background Service";         NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);         chan.setLightColor(Color.BLUE);         chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);                  NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);         assert manager != null;         manager.createNotificationChannel(chan);          NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);         Notification notification = notificationBuilder.setOngoing(true)                 .setContentTitle("App is running in background")                 .setPriority(NotificationManager.IMPORTANCE_MIN)                 .setCategory(Notification.CATEGORY_SERVICE)                 .build();         startForeground(2, notification);     }       @Override     public int onStartCommand(Intent intent, int flags, int startId) {         super.onStartCommand(intent, flags, startId);         startTimer();         return START_STICKY;     }       @Override     public void onDestroy() {         super.onDestroy();         stoptimertask();          Intent broadcastIntent = new Intent();         broadcastIntent.setAction("restartservice");         broadcastIntent.setClass(this, Restarter.class);         this.sendBroadcast(broadcastIntent);     }        private Timer timer;     private TimerTask timerTask;     public void startTimer() {         timer = new Timer();         timerTask = new TimerTask() {             public void run() {                 Log.i("Count", "=========  "+ (counter++));             }         };         timer.schedule(timerTask, 1000, 1000); //     }      public void stoptimertask() {         if (timer != null) {             timer.cancel();             timer = null;         }     }      @Nullable     @Override     public IBinder onBind(Intent intent) {         return null;     } } 

Create a Broadcast Receiver to respond to your custom defined broadcasts in Restarter.java

The broadcast with the action name "restartservice" which you just defined in YourService.java is now supposed to trigger a method which will restart your service. This is done using BroadcastReceiver in Android.

We override the built-in onRecieve() method in BroadcastReceiver to add the statement which will restart the service. The startService() will not work as intended in and above Android Oreo 8.1, as strict background policies will soon terminate the service after restart once the app is killed. Therefore we use the startForegroundService() for higher versions and show a continuous notification to keep the service running.

public class Restarter extends BroadcastReceiver {     @Override     public void onReceive(Context context, Intent intent) {         Log.i("Broadcast Listened", "Service tried to stop");         Toast.makeText(context, "Service restarted", Toast.LENGTH_SHORT).show();          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {             context.startForegroundService(new Intent(context, YourService.class));         } else {             context.startService(new Intent(context, YourService.class));         }     } } 

Define your MainActivity.java to call the service on app start.

Here we define a separate isMyServiceRunning() method to check the current status of the background service. If the service is not running, we start it by using startService().

Since the app is already running in foreground, we need not launch the service as a foreground service to prevent itself from being terminated.

Note that in onDestroy() we are dedicatedly calling stopService(), so that our overridden method gets invoked. If this was not done, then the service would have ended automatically after app is killed without invoking our modified onDestroy() method in YourService.java

public class MainActivity extends AppCompatActivity {     Intent mServiceIntent;     private YourService mYourService;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);          mYourService = new YourService();         mServiceIntent = new Intent(this, mYourService.getClass());         if (!isMyServiceRunning(mYourService.getClass())) {             startService(mServiceIntent);         }     }      private boolean isMyServiceRunning(Class<?> serviceClass) {         ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);         for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {             if (serviceClass.getName().equals(service.service.getClassName())) {                 Log.i ("Service status", "Running");                 return true;             }         }         Log.i ("Service status", "Not running");         return false;     }       @Override     protected void onDestroy() {         //stopService(mServiceIntent);         Intent broadcastIntent = new Intent();         broadcastIntent.setAction("restartservice");         broadcastIntent.setClass(this, Restarter.class);         this.sendBroadcast(broadcastIntent);         super.onDestroy();     } } 

Finally register them in your AndroidManifest.xml

All of the above three classes need to be separately registered in AndroidManifest.xml.

Note that we define an intent-filter with the action name as "restartservice" where the Restarter.java is registered as a receiver. This ensures that our custom BroadcastReciever is called whenever the system encounters a broadcast with the given action name.

<application     android:allowBackup="true"     android:icon="@mipmap/ic_launcher"     android:label="@string/app_name"     android:supportsRtl="true"     android:theme="@style/AppTheme">      <receiver         android:name="Restarter"         android:enabled="true"         android:exported="true">         <intent-filter>             <action android:name="restartservice" />         </intent-filter>     </receiver>      <activity android:name="MainActivity">         <intent-filter>             <action android:name="android.intent.action.MAIN" />             <category android:name="android.intent.category.LAUNCHER" />         </intent-filter>     </activity>      <service         android:name="YourService"         android:enabled="true" >     </service> </application> 

This should now restart your service again if the app was killed from the task-manager. This service will keep on running in background as long as the user doesn't Force Stop the app from Application Settings.

UPDATE: Kudos to Dr.jacky for pointing it out. The above mentioned way will only work if the onDestroy() of the service is called, which might not be the case certain times, which I was unaware of. Thanks.

like image 120
Sayan Sil Avatar answered Oct 14 '22 20:10

Sayan Sil


If your Service is started by your app then actually your service is running on main process. so when app is killed service will also be stopped. So what you can do is, send broadcast from onTaskRemoved method of your service as follows:

 Intent intent = new Intent("com.android.ServiceStopped");  sendBroadcast(intent); 

and have an broadcast receiver which will again start a service. I have tried it. service restarts from all type of kills.

like image 26
Vishal Maral Avatar answered Oct 14 '22 21:10

Vishal Maral