如何从最近的任务中杀死应用程序后重新启动服务

时间:2015-12-11 11:53:57

标签: android android-service restart background-service android-service-binding

我已经创建了一个服务来定期获取设备的当前位置。即使从最近打开的应用程序中清除了应用程序,我也希望该服务在后台运行。目前,该服务仅在后台运行,直到应用程序出现在最近打开的应用程序中,但在应用程序被刷掉(或以其他方式杀死)时立即停止。 我已经尝试过堆栈溢出中的各种帮助,但我无法解决这个问题。请帮忙。这是我的服务代码。

[array([1, 1, 1]), array([1, 1, 1]), array([2, 2, 2])]

4 个答案:

答案 0 :(得分:20)

覆盖服务中的onTaskRemoved()并使用警报管理器再次启动服务。以下是来自我们的应用程序的代码,它做同样的工作并正常工作:

@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);
}  

由于您可能希望定期发送位置,即使服务在内存不足(或出于任何原因)被杀死的情况下,我建议您处理uncaughtException以在N秒后重新启动它。这就是我们在完美运行的应用程序中所做的工作:

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);
        }
    };

注意:我认为我记得我在Kitkat上验证过,START_STICKY无法在Kitkat和更高的API级别上运行。请自行验证。

更多
当您定期发送loc时,您可能必须考虑深度睡眠模式。为了让您在深度睡眠中工作,请将WakefulBroadcastReceiver与AlarmManager结合使用。看看我的其他帖子How to use http in deep sleep mode

<强>更新
如果用户从“设置”中“强制停止”应用程序,则此解决方案不起作用(实际上不需要工作)。事实上这很好,因为如果用户自己想要停止应用程序,重新启动服务并不是一个好方法。所以,没关系。

答案 1 :(得分:0)

return Service.START_NOT_STICKY;替换为return START_STICKY;

答案 2 :(得分:0)

如果您想要从最近任务中杀死后重新启动服务,请使用

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

如果您使用START_STICKY,当您从最近的任务中删除应用时,您的服务将被终止(onTaskRemoved被解雇,onDestroy 被解雇那么它会再次自动启动(onCreate被解雇,onStartComand已被解雇)

答案 3 :(得分:-1)

我使用 android 9 ,该解决方案部分对我有效。 我有一个前台服务案例(工作24/7),我想在应用程序崩溃后重新启动。 捕获到事件render() { return ( /** * @see https://github.com/reduxjs/react-redux/blob/master/docs/api/Provider.md */ <Provider store={store}> {/** * PersistGate delays the rendering of the app's UI until the persisted state has been retrieved * and saved to redux. * The `loading` prop can be `null` or any react instance to show during loading (e.g. a splash screen), * for example `loading={<SplashScreen />}`. * @see https://github.com/rt2zz/redux-persist/blob/master/docs/PersistGate.md */} <PersistGate loading={<SplashScreen />} onBeforeLift={this.onBeforeLift} persistor={persistor}> {this.state.gateLifted ? <RootScreen LoginStatus={this.state.isLogin} /> : <SplashScreen />} {/* {<RootScreen LoginStatus={this.state.isLogin} />} */} </PersistGate> </Provider> ) } 时,除了uncaughtExceptionHandler事件外,应用程序也被冻结,在最新的Android版本中(我认为是O +),它不再起作用。 如果您需要更多活动的解决方案,那么我的应用程序只有一个活动有片段,只需使用this链接即可。 为了解决该问题,我添加了一个功能,该功能可以检查活动是否正常运行(以终止活动),以及一些终止活动的说明:

public void onTaskRemoved(Intent rootIntent) {

添加到清单:

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)
        }
    }
}