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?
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With