添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

安卓:应用被杀时保持服务运行

111 人关注

我想保持一个 IntentService 在后台运行,即使该应用程序被杀死。我所说的 "杀死 "是指 长时间按住home键 -> 查看所有正在运行的应用程序 -> 把我的应用程序放在一边 -> 应用程序被杀 OR 长时间按后退键 -> 应用程序被杀

我的代码如下。在我的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();

我看到,当应用程序运行时,该服务正在运行。open. It's still running when I 最小化应用程序通过home-button。它仍然在运行,当我关闭应用程序通过后退按钮。但如果我像上面提到的那样杀死它,它就会停止。我怎样才能解决这个问题?

5 个评论
我试了一下(下载了例子):是的,该服务在通过任务管理器杀死后仍能存活,但在 "长时间按后退键 "杀死后却不能存活。 你有什么想法?
这是否回答了你的问题? 应用程序关闭时安卓服务停止
也许我的答案对某人有用。 stackoverflow.com/a/64113820/2877427
这些天在所有的答案中,哪个是实际工作的?
android
service
background
intentservice
user2078872
user2078872
发布于 2015-05-29
9 个回答
Sayan Sil
Sayan Sil
发布于 2022-11-29
已采纳
0 人赞同

所有的答案似乎 correct 因此,我将继续努力,给 complete 在这里回答。

首先,要做你想做的事,最简单的方法是启动一个 广播 在安卓系统中,当 应用程序被杀死 手动,并定义一个自定义的 BroadcastReceiver 来触发之后的服务重启。

Now lets jump into code.

YourService.java 中创建你的服务

请注意 onCreate() 的方法,我们在这里开始一个 foreground service 对于Build版本大于 Android Oreo .这是因为最近引入了严格的通知政策,我们必须定义自己的 通知通道 以正确显示它们。

替换代码4】方法中的 this.sendBroadcast(broadcastIntent); 是异步发送一个带有行动名称的广播的语句。 "restartservice" .我们稍后将使用这个作为触发器来重新启动我们的服务。

在这里,我们定义了一个简单的定时器任务,它每隔一段时间就会打印一个计数器的值。 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();
            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 广播 Receiver to respond to your custom defined broadcasts in Restarter.java

带有行动名称的广播"restartservice"你刚才在YourService.java中定义的方法,现在应该触发一个方法,该方法将重新启动你的服务. This is done using BroadcastReceiver在安卓系统中。

We override the built-in onRecieve() method in BroadcastReceiver来添加将重启服务的语句。替换代码14】将不顺畅在及以上的安卓奥利奥8.1,因为严格的背景政策 will soon terminate the service after restart once the 应用程序被杀死. 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));

定义你的MainActivity.java,在应用程序启动时调用服务。

这里我们定义了一个单独的isMyServiceRunning()方法来检查后台服务的当前状态。如果该服务是not运行,我们通过使用startService()来启动它。

由于应用程序已经在前台运行,所以我们不需要将服务作为一个启动程序。foreground service以防止自己被终止。

请注意,在onDestroy()中我们专门调用了stopService(),这样我们的overridden method被调用。如果没有这样做,那么该服务就会结束自动地 after 应用程序被杀死 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();

最后在你的AndroidManifest.xml中注册它们。

上述三类人都需要分别注册在AndroidManifest.xml.

请注意,我们定义的intent-filter行动名称"restartservice",其中Restarter.java被注册为receiver。 这确保了我们的定制BroadcastReciever每当系统遇到一个具有给定值的广播,就会调用行动名称.

<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 重新启动你的服务 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该应用程序来自应用程序设置.

更新。 Kudos to Dr.jacky指出了这一点。上述方式只有在服务的onDestroy()被调用时才会起作用,这可能是not某些时候是这样的,我没有意识到。谢谢。

在奥利奥中,当应用程序被杀死或背景时,它仍然不能在后台工作。...请帮助解决这个问题。
Sayan Sil
你是在MIUI上测试它吗?如果是的话,我很抱歉地说,他们有一个严格的后台任务政策,他们无条件地杀死所有不在他们白名单上的应用程序。
该处的 onDestroy 可能没有被调用。 stackoverflow.com/a/7237522/421467
谢谢!我更新了我的答案,以确保这种可能性是已知的。我今天学到了一些新东西。
当我们已经从onStartCommand()返回了START_STICKY,这意味着如果服务被杀死,操作系统将重新启动。那么为什么我们需要在服务的onDestroy()中启动一个服务的广播呢?重新启动不是已经由操作系统处理了吗?
Vishal Maral
Vishal Maral
发布于 2022-11-29
0 人赞同

如果你的服务是由你的应用程序启动的,那么实际上你的服务是在主进程中运行的。所以当应用程序被杀死时,服务也会被停止。所以你可以做的是,从你的服务的 onTaskRemoved 方法中发送广播,如下所示。

 Intent intent = new Intent("com.android.ServiceStopped");
 sendBroadcast(intent);

并有一个广播接收器,它将再次启动一个服务。我已经试过了。服务从所有类型的杀戮中重新启动。

这就是正确的答案。我已经写了一个简单的例子,在一个 blog entry
请告诉我,我在意图中写的意思是 "com.android.ServiceStopped",这是什么意思,我在sendBroadcast方法中调用的意图是创建一个新的意图来停止服务。
@BhendiGawaar 我做了和你说的一样的事情。但它在定制的操作系统手机上不起作用,如vivo、OPO、MIUI等。
有时,当安卓指定它需要杀死一些进程以释放更多的内存时,它甚至不调用 onTaskRemoved 形式的服务。它只是杀了它。
我使用的是联想TB3-730X。当应用程序被用户杀死时,onTaskRemoved没有被调用,我也尝试了onDestroy。它也没有工作。请建议我任何解决方案。
Iman Marashi
Iman Marashi
发布于 2022-11-29
0 人赞同

在你的服务中,添加以下代码。

@Override
public void onTaskRemoved(Intent rootIntent){
    Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
    restartServiceIntent.setPackage(getPackageName());
    PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
    AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
    alarmService.set(
    AlarmManager.ELAPSED_REALTIME,
    SystemClock.elapsedRealtime() + 1000,
    restartServicePendingIntent);
    super.onTaskRemoved(rootIntent);
    
为了摆脱 "缺少PendingIntent可变性标志 "的警告,请将 PendingIntent.FLAG_ONE_SHOT 替换为 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE
kiturk3
kiturk3
发布于 2022-11-29
0 人赞同

在onstart命令中加入 START_STICKY ...这个服务不会被杀死,除非它做了太多的任务,而内核想为此杀死它......

@Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.i("LocalService", "Received start id " + startId + ": " + intent);
            // We want this service to continue running until it is explicitly
            // stopped, so return sticky.
            return START_STICKY;
    
通过任务管理器进行杀毒,但在 "长时间按后退键 "杀毒的情况下,该服务无法存活 :/
start sticky将在应用程序关闭后再次运行该服务,所以从某种意义上说,它将重新启动该服务。
在某些时候,如果用户杀死了这个应用程序,也许我们应该尊重用户,让服务死亡。
Rishit Shah
Rishit Shah
发布于 2022-11-29
0 人赞同

原因是你试图使用一个IntentService。下面是来自 API文件

The IntentService does the following:

在处理完所有的启动请求后停止服务,所以你永远不必调用stopSelf()。 所以你不必再调用stopSelf()。

因此,如果你想让你的服务无限期地运行,我建议你扩展服务类来代替。然而,这并不能保证你的服务会无限期地运行。如果你的服务是低优先级的,它仍然有机会在低内存状态下被内核杀死。
1)通过调用 startForeground() 方法使其在前台运行。
2)如果服务被杀死了,就重新启动它。 下面是文档中的一部分例子,他们谈到了在服务被杀死后重新启动的问题

 public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
      // For each start request, send a message to start a job and deliver the 
      // start ID so we know which request we're stopping when we finish the job 
      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      mServiceHandler.sendMessage(msg);
      // If we get killed, after returning from here, restart 
      return START_STICKY;
    
waseem
waseem
发布于 2022-11-29
0 人赞同

在你的服务类中使用onTaskRemoved

 @Override
    public void onTaskRemoved(Intent rootIntent) {
        Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
        PendingIntent restartServicePendingIntent = PendingIntent.getService(
                getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
        AlarmManager alarmService = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmService.set(AlarmManager.ELAPSED_REALTIME, elapsedRealtime() + 500,
                restartServicePendingIntent);
        Log.d("taskremoved", "task removed ");
        super.onTaskRemoved(rootIntent);
    
Mia
针对S+(版本31及以上),在创建PendingIntent时,需要指定FLAG_IMMUTABLE或FLAG_MUTABLE中的一个。
Melbourne Lopes
Melbourne Lopes
发布于 2022-11-29
0 人赞同

你可以在清单中使用 android:stopWithTask="false" ,这意味着即使用户通过从任务列表中删除应用程序来杀死它,你的服务也不会停止。

 <service android:name=".service.StickyService"
                  android:stopWithTask="false"/>
    
这是默认的错误!!
Apple Yellow
Apple Yellow
发布于 2022-11-29
0 人赞同

You try below code:

public class HeartbeartService extends Service {
private static final int SERVICE_NOTIFICATION_ID = 54321;
private static final String CHANNEL_ID = "Notification service";
private final LocalBinder mBinder = new LocalBinder();
Handler handler = new Handler();
private Runnable runnableCode = new Runnable() {
    @Override
    public void run() {
        Context context = getApplicationContext();
        Intent myIntent = new Intent(context, HeartbeatEventService.class);
        context.startService(myIntent);
        HeadlessJsTaskService.acquireWakeLockNow(context);
        handler.postDelayed(this, 2000);
public class LocalBinder extends Binder {
    public HeartbeartService getService() {
        return HeartbeartService.this;
private void createNotificationChannel() {
    // Create the NotificationChannel, but only on API 26+ because
    // the NotificationChannel class is new and not in the support library
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        int importance = NotificationManager.IMPORTANCE_MIN;
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "Notification service", importance);
        channel.setDescription("CHANEL DESCRIPTION");
        NotificationManager notificationManager = getSystemService(NotificationManager.class);
        notificationManager.createNotificationChannel(channel);
public void onDestroy() {
    super.onDestroy();
    this.handler.removeCallbacks(this.runnableCode);
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    this.handler.post(this.runnableCode);
     createNotificationChannel();
     Intent notificationIntent = new Intent(this, MainActivity.class);
     PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent,
             PendingIntent.FLAG_CANCEL_CURRENT);
     Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
             .setContentTitle("Notification service")
             .setContentText("Running...")
             .setBadgeIconType(0)
             .setAutoCancel(false)
             .setOngoing(true)
             .build();
    startForeground(1, notification);
    return START_STICKY;
    
请补充说明。
你需要解释什么?我希望可以帮助你。Ajay Chauhan
Manisha Saini
Manisha Saini
发布于 2022-11-29
0 人赞同

以下是我如何在应用程序处于后台或甚至使用前台服务杀死时触发我的警报。

  // Aware user about the foreground service
   private fun setForeGroundNotification() {
    val intent = Intent(this, AlarmForegroundService::class.java)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForegroundService(intent)
    } else {
        startService(intent)
public void onCreate() {
    super.onCreate();
    final String CHANNELID = "Foreground Service ID";
    NotificationChannel channel;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        channel = new NotificationChannel(
                CHANNELID,
                CHANNELID,
                NotificationManager.IMPORTANCE_LOW
        getSystemService(NotificationManager.class).createNotificationChannel(channel);
        Notification.Builder notification = new Notification.Builder(this, CHANNELID)
                .setContentTitle("App is running in background to check alarm")
                .setContentText("Checking Alarm..")
                .setAutoCancel(false)
                .setSmallIcon(R.mipmap.logo);
        startForeground(1, notification.build());
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    int hours = intent.getIntExtra("hours", 0);
    int minutes = intent.getIntExtra("minutes", 0);
    //Firing alarm at selected wake up time
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY, hours);
    calendar.set(Calendar.MINUTE, minutes);
    //To prevent alarm trigger for past time.
    if (calendar.before(Calendar.getInstance())) {
        calendar.add(Calendar.DATE, 1);
    Intent intent1 = new Intent(this, AlarmReceiver.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(
            this,
            intent1,
            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
    AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), (1000 * 60 * 60 * 24), pendingIntent);
    return super.onStartCommand(intent, flags, startId);
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
    val intent = Intent(context, AlarmIntentService::class.java)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context!!.startForegroundService(intent)
    } else {
        context!!.startService(intent)
public class AlarmIntentService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
@Override
public void onCreate() {
    super.onCreate();
    NotificationChannel channel = null;
    int notificationId = 123;
    long[] vibPattern = {1000, 1000, 1000, 1000};
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        channel = new NotificationChannel("channel2",
                "Sleep Alarm",
                NotificationManager.IMPORTANCE_HIGH);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        channel.setVibrationPattern(vibPattern);
    NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        manager.createNotificationChannel(channel);
    //Creating the notification object
    NotificationCompat.Builder notification = new NotificationCompat.Builder(this, "channel2");
    notification.setSmallIcon(R.drawable.ic_bell);
    notification.setContentTitle("Wake up Alarm!!");
    notification.setContentText("It's time to get up");
    notification.setAutoCancel(true);
    notification.setSound(null);
    //notification.build().flags |= Notification.FLAG_AUTO_CANCEL;
    //Action button handling
    Intent onDismiss = new Intent(this, DismissReceiver.class);
    onDismiss.putExtra("NOTIFICATION_ID", notificationId);
    Intent onSnooze = new Intent(this, SnoozeReceiver.class);
    SharedPreferences sh = getSharedPreferences("MySharedPref", Context.MODE_PRIVATE);
    int snooze = sh.getInt("snooze", 0);
    PendingIntent dismissPendingIntent = PendingIntent.getBroadcast(this, 1, onDismiss, PendingIntent.FLAG_IMMUTABLE);
    if (snooze == 0) {
        notification.setContentIntent(dismissPendingIntent);
        notification.addAction(R.drawable.ic_cross, "Dismiss", dismissPendingIntent);
    } else {
        PendingIntent snoozePendingIntent = PendingIntent.getBroadcast(this, 1, onSnooze, PendingIntent.FLAG_IMMUTABLE);
        notification.setContentIntent(dismissPendingIntent);
        notification.setContentIntent(snoozePendingIntent);
        notification.addAction(R.drawable.ic_cross, "Dismiss", dismissPendingIntent);
        notification.addAction(R.drawable.ic_cross, "Snooze", snoozePendingIntent);
    //To trigger the chosen alarm ringtone
    Intent startIntent = new Intent(this, RingtonePlayingService.class);
    this.startService(startIntent);