How to restart service after the app is killed from recent tasks

后端 未结 4 729
执念已碎
执念已碎 2020-12-01 04:43

I have created a service to fetch current location of the device in periodic intervals. I want the service to run in the background even if the app is cleared from recently

相关标签:
4条回答
  • 2020-12-01 05:09

    Override onTaskRemoved() in your service and use alarm manager to start the service again. Below is code from our app that does the same and works fine:

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
    
        Log.d(TAG, "TASK REMOVED");
    
        PendingIntent service = PendingIntent.getService(
                getApplicationContext(),
                1001,
                new Intent(getApplicationContext(), MyService.class),
                PendingIntent.FLAG_ONE_SHOT);
    
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
    }  
    

    As you may want to send location periodically even in the case if the service gets killed on low memory (or for any reason), I suggest you to handle the uncaughtException to restart it after N seconds. This is how we have done in our app that works perfectly:

    private Thread.UncaughtExceptionHandler defaultUEH;
    private Thread.UncaughtExceptionHandler uncaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
    
        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
            Log.d(TAG, "Uncaught exception start!");
            ex.printStackTrace();
    
            //Same as done in onTaskRemoved()
            PendingIntent service = PendingIntent.getService(
                    getApplicationContext(),
                    1001,
                    new Intent(getApplicationContext(), MyService.class),
                    PendingIntent.FLAG_ONE_SHOT);
    
            AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
            alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
            System.exit(2);
            }
        };
    

    Note: I THINK and I remember I verified it on Kitkat that START_STICKY does not work on Kitkat and higher API levels. Please verify this for yourself.

    MORE:
    As you do loc sending periodically, you may have to consider the deep sleep mode. To get things work in deep sleep, use WakefulBroadcastReceiver combined with AlarmManager. Take a look at my other post How to use http in deep sleep mode.

    UPDATE:
    This solution does not work (in fact need not to work) if user "FORCE STOP" the application from Settings. This is good in fact as restarting the service is not a good way if user himself wants to stop application. So, it is fine.

    0 讨论(0)
  • 2020-12-01 05:11

    If you ONLY want to restart service after it kill from Recent Task, simple use

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }
    

    If you use START_STICKY, when you kill app from recent task, your service will be killed (onTaskRemoved fired, onDestroy NOT fired) THEN it will auto start again (onCreate fired, onStartComand fired)

    0 讨论(0)
  • 2020-12-01 05:12

    replace return Service.START_NOT_STICKY; with return START_STICKY;

    0 讨论(0)
  • 2020-12-01 05:21

    I use android 9 and the solution works partially for me. I had a case with foreground service (working 24/7), which I wanted to restart after the application was crashed. When the event uncaughtExceptionHandler was caught, the application got frozen besides public void onTaskRemoved(Intent rootIntent) { event doesn't work anymore in latest Android versions (I suppose O+). My application has only one activity with fragments if you need solution for more activities just use this link. To solve that problem I've added a function which checks if the activity is working (to kill it) and some instructions to kill the process:

    class MyApplication : Application() {
    
        private var currentActivity: Activity? = null
    
        override fun onCreate() {
            super.onCreate()
            StorageManager.init()
    
            this.registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
                override fun onActivityPaused(activity: Activity) {
    
                }
    
                override fun onActivityStarted(activity: Activity) {
                    currentActivity = activity
                }
    
                override fun onActivityDestroyed(activity: Activity) {
                }
    
                override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
                }
    
                override fun onActivityStopped(activity: Activity) {
                    currentActivity = null
                }
    
                override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                }
    
                override fun onActivityResumed(activity: Activity) {
                }
            })
    
            Thread.setDefaultUncaughtExceptionHandler { _, e ->
                // Close current activity
                currentActivity?.finish()
    
                val service : PendingIntent? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    // Start service in Oreo and latest
                    PendingIntent.getForegroundService(
                        applicationContext,
                        8888,
                        Intent(applicationContext, SensorService::class.java),
                        PendingIntent.FLAG_ONE_SHOT)
                } else {
                    // Start service in Nougat and older
                    PendingIntent.getService(
                        applicationContext,
                        8888,
                        Intent(applicationContext, MyService::class.java),
                        PendingIntent.FLAG_ONE_SHOT)
                }
    
                // The great solution introduced by @cgr
                val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
                alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service)
    
                // Kill the current application process to avoid freezing activity
                android.os.Process.killProcess(android.os.Process.myPid())
                exitProcess(10)
            }
        }
    }
    

    Add to manifest:

        <application
            android:name="com.example.MyApplication"
            ...
    
    0 讨论(0)
提交回复
热议问题