18

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 force stop, and I all the time see Instagram app running, even when I kill it, it's just restart automatically and it's once again there.

So, what is a way to make app running constantly? I'm doing app with reminders and need to show notifications in specific time, regardless how app was previously closed before.

azizbekian
  • 60,783
  • 13
  • 169
  • 249
silent_coder
  • 6,222
  • 14
  • 47
  • 91

6 Answers6

2

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));
    }
}  
Sagar Damani
  • 862
  • 7
  • 12
  • 1
    First, if you stop the app from "Settings -> Apps -> Running" tab, the service won't start again. Second, if it even worked the way you mentioned, it will enforce you to have running service in any situation, which is most possibly not what you want. – azizbekian Apr 08 '17 at 22:21
  • Returning super like that in a Service is wrong as well I'm afraid – David Rawson Apr 15 '17 at 04:26
  • Starting from api level 26 you cannot start a service from Application class – Shubham Goel Feb 18 '19 at 06:41
1

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.

Community
  • 1
  • 1
azizbekian
  • 60,783
  • 13
  • 169
  • 249
1

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.

Remario
  • 3,813
  • 2
  • 18
  • 25
1

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.

androCoder-BD
  • 498
  • 7
  • 13
0

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.

tingyik90
  • 1,641
  • 14
  • 23
-1

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.

Community
  • 1
  • 1
David Rawson
  • 20,912
  • 7
  • 88
  • 124