Looks like force stop should prevent app from running and it\'s even disable all app\'s alarms. However I found that notification in Google Calendar still shown fine even after
If you start a service in Application Class than your service will be always running even though if a user terminates or force stop from task manager, it will run again.
To create service specifically in Android studio Right click on app from Project Explorer and then New > Service > Service
Create a service:
public class ServiceName extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// do your jobs here
return super.onStartCommand(intent, flags, startId);
}
}
Now create an Application Class and start Service in Application Class
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
startService(new Intent(this, ServiceName.class));
}
}
Displaying notifications is a common functionality of Android Services and there are already many questions on how to prevent Services from being stopped/or from force close.
The relevant questions are listed below:
Android: How to auto-restart application after it's been "force closed"?
How to prevent android service getting killed (Service with notification)
How to restart a service in android?
Keep Service running
Restart the service even if app is force-stopped and Keep running service in background even after closing the app How?
To summarise them, the first step is to implement a BroadcastReceiver
that listens for BOOT_COMPLETED
. This will mean that your service becomes active when the Android device is turned on. To do this, you put the following code in the manifest:
<receiver android:name=".MyBootCompletedReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
Make sure also to include the completed boot permission:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
Then implement the BroadcastReceiver:
public class MyBootCompletedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent myService = new Intent(context, MyLongRunningService.class);
context.startService(myService);
}
}
When you start the Service, you can return START_STICKY which will tell the Android OS to restart the service if it is squashed by the OS in conditions of limited resources:
public class MyLongRunningService extends Service {
@Override
public void onCreate() {
super.onCreate();
//inject dependencies if necessary
}
public int onStartCommand(Intent intent, int flags, int startId) {
//setup, then
return START_STICKY;
}
}
In general, Services launched by apps will be stopped by the Android OS when the device is low on resources. Returning START_STICKY
tells the OS to restart the Service if it has to be stopped. Hence, by ensuring the Service is started when the device is turned on and by requesting it to be restarted if it is stopped under conditions of low resource, you have made a Service that runs constantly.
This is the most basic pattern for ensuring your Service (and hence Application) is running all the time, which was your requirement.
There are additional measures on top of that which you can take which are outlined in the other answers here, but they should be seen as a supplement to implementing a Service that starts on BOOT_COMPLETED
and that requests restart if it is stopped in conditions of low resources.
I see two options there.
First one is to handle any exception via Thread.setDefaultUncaughtExceptionHandler() that is shipping with Java, it's not from Android SDK.
To be concise, you make your custom Application
class implement UncaughtExceptionHandler
and register it as a listener to any exception in the application. As soon as some crash happens this callback will be fired from where you can delay a job to happen in near future (e.g. spawn AlarmManager
to launch the app again in 50ms).
The second option is that you can launch your components in different processes. From docs:
android:process
The name of the process where the service is to run. Normally, all components of an application run in the default process created for the application. It has the same name as the application package. The element's process attribute can set a different default for all components. But component can override the default with its own process attribute, allowing you to spread your application across multiple processes.
A crash that happens on different process won't make the process that hosts your UI to crash.
Based on my limited knowledge, you need to use AlarmManager
, WakefulBroadcastReceiver
and create a Service
or IntentService
for all these background task. Read more about it here. I have a service that I used for my Firebase messaging app and it works fine even after user killed the app. In my case, I connect to Firebase at fixed period using the following service.
First, I have the following class to set the AlarmManager
.
public class FirebaseHandler {
private Context context;
private static final long FIREBASE_ALARM_CYCLE_TIME = 300000;
// constructors
public FirebaseHandler(Context context) {
this.context = context;
}
// set alarm
public void setAlarm() {
// create pending intent
Intent intent = new Intent(context, AlarmReceiver.class);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
AlarmReceiver.ALARM_REQUEST_CODE,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// create alarm
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarm.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + FIREBASE_ALARM_CYCLE_TIME,
FIREBASE_ALARM_CYCLE_TIME,
pendingIntent);
}
}
I just initiate this by calling new FirebaseHandler(getApplicationContext()).setAlarm()
somewhere in the activity. The AlarmReceiver
class is as below.
public class AlarmReceiver extends WakefulBroadcastReceiver {
public static final int ALARM_REQUEST_CODE = 12345;
@Override
public void onReceive(Context context, Intent wakefulIntent) {
Intent intent = new Intent(context, FirebaseAlarmService.class);
startWakefulService(context, intent);
}
}
The FirebaseAlarmService
class is as below.
public class FirebaseAlarmService extends Service {
private static final String CLASSNAME = FirebaseAlarmService.class.getSimpleName();
private HandlerThread handlerThread;
// onStartCommand
@Override
public int onStartCommand(final Intent intent, int flags, final int startId) {
// start a new thread
// this depends on your need. I need to do a continuous operation for some time
// you can use IntentService too
handlerThread = new HandlerThread(CLASSNAME);
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
Runnable runnable = new Runnable() {
@Override
public void run() {
// all your codes here for the background task...
// remember to release the wake lock and stop service
AlarmReceiver.completeWakefulIntent(wakefulIntent);
stopSelf();
}
return START_NOT_STICKY;
}
// this is the part that does the trick
@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
// when the service is killed, start it again
new FirebaseHandler(getApplicationContext()).setAlarm();
}
// onDestroy
@Override
public void onDestroy() {
super.onDestroy();
// make sure to quit the thread
handlerThread.quit();
}
}
In summary, FirebaseHandler
sets an AlarmManager
, which will call WakefulBroadcastReceiver
periodically, which will starts a Service
periodically. When the service is killed, the service itself will start the AlarmManager
again onTaskRemoved
.
In the AndroidManifest
, you'll need to add in the following permission for wake lock.
<uses-permission android:name="android.permission.WAKE_LOCK" />
Also remember to add the receiver.
<receiver
android:name=".receiver.AlarmReceiver"
android:process=":remote" />
BONUS: You might want to start the service once the phone is rebooted or the app is updated via PlayStore. Create another WakefulBroadcastReceiver
.
public class BootBroadcastReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(Context context, Intent wakefulIntent) {
// check if user is login, then set the alarm
if (isLogin) {
new FirebaseHandler(context).setAlarm();
}
// remove wake lock
WakefulBroadcastReceiver.completeWakefulIntent(wakefulIntent);
}
}
In the AndroidManifest
, add the required permission.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Add the intent filter.
<receiver android:name=".receiver.BootBroadcastReceiver">
<intent-filter>
<!-- get notified on reboot -->
<action android:name="android.intent.action.BOOT_COMPLETED" />
<!-- get notified on app updated -->
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
TIPS: Sometimes you'll find that the above method will not work. This is mostly not your fault. It is the phone's security settings that caused this, especially Mi phones. User will need to "trust" the app and enable "auto-start" in the phone settings, then everything should work just fine.
Well for starters they have a job scheduler system that schedules jobs to executed, these jobs can be stopped , started or resumed. They implement a mechanism to detect crash, think java-script where if a application crashes it can be restarted (nodemon or forever) , in android there are services, which can be started or resume, There is this special service behavior to restart crashed services.
START_REDELIVER_INTENT- tells the system to restart the service after the crash and also redeliver the intents that were present at the time of crash.
The Android 5.0 Lollipop (API 21) release introduces a job scheduler API via the JobScheduler class. This API allows to batch jobs when the device has more resources available. In general this API can be used to schedule everything that is not time critical for the user.
You can also mix Alarms, broadcast receivers and threading coupled with reactive programming to perform the job.Alarms (based on the AlarmManager class) give you a way to perform time-based operations outside the lifetime of your application. For example, you could use an alarm to initiate a long-running operation, such as starting a service once a day to download a weather forecast.
You can attach observables to certain tasks performing specific operations, You can implement asynchronous i/o, computational operations, or even “infinite” streams of data by designing your own Observable.
Just to add with Sagar Damani's answer, A service call is required to run your long operation in background but they also run in sepearate processes. When you declare a service or an activity in the androidMenifes.xml, also add the android:process="" attribute. Therefore, it will always be persistent if the user kills/force stop the activity.