【问题标题】:The process of the service is killed after the application is removed from the application tray应用程序从应用程序托盘中删除后,服务的进程被杀死
【发布时间】:2013-12-15 07:46:41
【问题描述】:

我在启动活动时启动服务(或重新启动正在运行的服务),使用:

Intent intent = new Intent(this, MyService.class); startService(intent);

稍后基于某些操作,相同的活动使用绑定到服务

bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE);

当活动被销毁时,我调用

unbindService(mConnection);

之前,当我从应用程序托盘中杀死相同的活动/应用程序并在正在运行的应用程序下显示“消息 1 进程 1 服务正在运行”时,该服务用于重新启动。

现在,服务不会在杀死相同的活动/应用程序时重新启动。

我收到消息“0 process 1 service running”,这意味着该服务实际上没有运行。

应用程序关闭时服务不会重新启动。我的应用程序包含一项活动。系统启动后启动服务也成功启动。

当我使用 startService() 启动服务时,为什么服务的进程会被杀死??

编辑

在我从应用程序托盘关闭应用程序后,该服务用于较早地重新启动。但现在突然有了相同的代码,它没有。当我关闭它们时,其他应用程序也会发生这种情况。例如。

【问题讨论】:

标签: android android-service


【解决方案1】:

这是我遇到的一种解决方法,如果它的进程在关闭应用程序时被终止,它适用于重新启动服务。在您的服务中,添加以下代码。

我在this 线程中遇到了这个解决方法。

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

似乎是应用程序进程被杀死的错误。如果服务的进程被杀死,服务就没有运行的意义。

【讨论】:

  • 当我将应用程序滑出应用程序托盘时,“onTaskRemoved”回调被调用但服务没有启动,为什么?
  • @geekkoraul 它不起作用,android 5.0 有什么变化吗??
  • 优秀的解决方案,关闭+1人时强制启动服务的最佳方式
  • 但是当我像一加 x 手机一样杀死应用程序时,这个 onTaskRemoved 方法不会调用,所以这对我不起作用,而且大多数手机都会发生这种情况。
【解决方案2】:

请注意:onDestroy 并不总是被调用。您不应该这样放置代码。
当activity强制关闭或系统异常关闭时,onDestroy不会被调用。

【讨论】:

    【解决方案3】:

    很遗憾,由于 Android 的工作方式,这是一个复杂的问题。有许多策略可以解决问题的不同部分。 为了获得最佳效果,请将多种策略组合在一起。

    请注意,在较新的 Android 版本中,其中一些策略可能不再需要。

    1。开始活动

    做什么

    取自Foreground service killed when receiving broadcast after acitivty swiped away in task list

    在前台服务中:

      @Override
        public void onTaskRemoved( Intent rootIntent ) {
           Intent intent = new Intent( this, DummyActivity.class );
           intent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
           startActivity( intent );
        }
    

    在清单中:

      <activity
        android:name=".DummyActivity"
        android:theme="@android:style/Theme.NoDisplay"
        android:enabled="true"
        android:allowTaskReparenting="true"
        android:noHistory="true"
        android:excludeFromRecents="true"
        android:alwaysRetainTaskState="false"
        android:stateNotNeeded="true"
        android:clearTaskOnLaunch="true"
        android:finishOnTaskLaunch="true"
        /> 
    

    (如果您的服务在不同的进程中,则将此活动的进程设置为同一进程。)

    在 DummyActivity.java 中:

      public class DummyActivity extends Activity {
            @Override
            public void onCreate( Bundle icicle ) {
                super.onCreate( icicle );
                finish();
            }
        }
    

    副作用

    导致最近的活动关闭。通常,滑动应用不会关闭最近的活动。

    缺点

    这只会在when the dummy activity starts 生效,可能需要半秒或更长时间,所以这仍然会使服务暂时被杀死。

    说明

    当您删除/滑动您的应用程序时,一个名为 waitingToKill 的标志是 set。设置此标志后,Android 可能会终止进程at any point in the future,例如when you receive a broadcast。开始活动clears this flag.

    2。用foreground broadcastsBroadcastReceiver 发送垃圾邮件

    做什么

    将其合并到您的服务代码中:

    if (Build.VERSION.SDK_INT >= 16) {
        Intent intent = new Intent(this, DummyReceiver.class);
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    
        //This seems to be timing-related; the more times we do this,
        //the less likely the process gets killed
        for (int i = 0; i < 50; ++i)
            sendBroadcast(intent);
    }
    

    创建一个虚拟广播接收器:

    public class DummyReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {}
    }
    

    将接收器添加到您的清单中:

    <receiver android:name=".DummyReceiver" />
    

    副作用

    当任务从最近的屏幕中移除时,可能会导致轻微的延迟(~250 毫秒)。

    缺点

    这只会在接收广播时保持进程处于活动状态。 waitingToKill 标志仍然设置,因此该进程可能在之后仍会被终止,例如在接收到广播时。

    说明

    如果您的进程没有以前台优先级运行,Android will try to kill it immediately。接收前台广播会暂时阻止这种情况,从而改为设置 waitingToKill 标志。

    3。不要绑定到服务

    Binding to a service seems to increase the likelihood of the service's process being killed immediately when a task is removed.

    【讨论】:

      【解决方案4】:

      我知道这个问题很老,但我最近遇到了这个问题,突然我的服务在关闭应用程序时停止了。早些时候它工作正常。这个问题浪费了我很多时间。对于有类似问题的其他人,请确保您的背景数据限制已关闭。 这是我遇到的问题,它实际上是有道理的,因为当后台数据受限时,后台进程将无法运行。

      【讨论】:

        【解决方案5】:

        onDestroy 并不总是被调用。在您的情况下,主要问题是您无法在应用关闭时启动服务,那时 android OS(In Some OS) 会杀死服务,如果您无法重新启动服务,请调用警报管理器以像这样启动接收器,

        清单是,

                 <service
                    android:name=".BackgroundService"
                    android:description="@string/app_name"
                    android:enabled="true"
                    android:label="Notification" />
                <receiver android:name="AlarmReceiver">
                    <intent-filter>
                        <action android:name="REFRESH_THIS" />
                    </intent-filter>
                </receiver>
        

        IN Main Activty 这样启动报警管理器,

        String alarm = Context.ALARM_SERVICE;
                AlarmManager am = (AlarmManager) getSystemService(alarm);
        
                Intent intent = new Intent("REFRESH_THIS");
                PendingIntent pi = PendingIntent.getBroadcast(this, 123456789, intent, 0);
        
                int type = AlarmManager.RTC_WAKEUP;
                long interval = 1000 * 50;
        
                am.setInexactRepeating(type, System.currentTimeMillis(), interval, pi);
        

        这将调用reciver,reciver是,

        public class AlarmReceiver extends BroadcastReceiver {
            Context context;
        
            @Override
            public void onReceive(Context context, Intent intent) {
                this.context = context;
        
                System.out.println("Alarma Reciver Called");
        
                if (isMyServiceRunning(this.context, BackgroundService.class)) {
                    System.out.println("alredy running no need to start again");
                } else {
                    Intent background = new Intent(context, BackgroundService.class);
                    context.startService(background);
                }
            }
        
            public static boolean isMyServiceRunning(Context context, Class<?> serviceClass) {
                ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
                List<ActivityManager.RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
        
                if (services != null) {
                    for (int i = 0; i < services.size(); i++) {
                        if ((serviceClass.getName()).equals(services.get(i).service.getClassName()) && services.get(i).pid != 0) {
                            return true;
                        }
                    }
                }
                return false;
            }
        }
        

        这个Alaram接收器在android应用打开和应用关闭时调用一次。所以服务是这样的,

        public class BackgroundService extends Service {
            private String LOG_TAG = null;
                
            @Override
            public void onCreate() {
                super.onCreate();
                LOG_TAG = "app_name";
                Log.i(LOG_TAG, "service created");
            }
        
            @Override
            public int onStartCommand(Intent intent, int flags, int startId) {
                Log.i(LOG_TAG, "In onStartCommand");
                //ur actual code
                return START_STICKY;
            }
        
            @Override
            public IBinder onBind(Intent intent) {
                // Wont be called as service is not bound
                Log.i(LOG_TAG, "In onBind");
                return null;
            }
        
            @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
            @Override
            public void onTaskRemoved(Intent rootIntent) {
                super.onTaskRemoved(rootIntent);
                Log.i(LOG_TAG, "In onTaskRemoved");
            }
        
            @Override
            public void onDestroy() {
                super.onDestroy();
                Log.i(LOG_TAG, "In onDestroyed");
            }
        }
        

        【讨论】:

          【解决方案6】:

          当没有绑定到服务或成熟的前台时,android 系统会将该服务识别为应关闭的未使用的重载服务。即使应用程序关闭,这是维护服务的最佳方式:AlarmManager or Service

          【讨论】:

          • 既然你之前它工作得很好,那么我能想到的是kitkat版本的问题需要修复它有错误,很抱歉我没有其他解决方法.. .
          • 这是我发现的一个线程,它解决了这个问题。似乎是 4.4.1 和 4.4.2 中的一个错误 groups.google.com/forum/#!topic/android-developers/H-DSQ4-tiac
          猜你喜欢
          • 1970-01-01
          • 2020-12-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-09-19
          • 1970-01-01
          • 2020-05-11
          相关资源
          最近更新 更多