【问题标题】:Android Service Stops When App Is Closed关闭应用程序时Android服务停止
【发布时间】:2013-05-15 02:22:34
【问题描述】:

我正在从我的主要 Android 活动启动一项服务,如下所示:

final Context context = base.getApplicationContext();
final Intent intent = new Intent(context, MyService.class);
startService(intent);

当我通过从最近的应用程序列表中刷出活动页面来关闭活动页面时,该服务会停止运行并在一段时间后重新启动。由于我的应用程序要求,我无法将持久服务与通知一起使用。如何使服务不重启或关闭,而在应用退出时继续运行?

【问题讨论】:

  • @kiran 我面临的问题是当活动关闭时服务会重新启动。我正在寻找一种方法来保持服​​务始终运行(在活动完成后不重新启动)。
  • 我觉得我们无法做到这一点。在资源不足的情况下,您的服务将被终止。我们能希望的最好的结果就是重新开始。而在 4.4+ 上,swipe kill 甚至不会重新启动服务。请阅读此thread
  • 认真考虑您是否真的需要您的服务一直运行:这对功耗和内存消耗不利。

标签: android service android-activity restart shutdown


【解决方案1】:

我处于同样的情况,到目前为止,我了解到当应用程序关闭时,服务也会关闭,因为它们在一个线程中,所以服务应该在另一个线程上以使其不被关闭,对此进行调查,并在此处使用警报管理器使服务保持活动状态,例如 http://www.vogella.com/articles/AndroidServices/article.html 这样您的服务将不会显示在通知中。

最后,经过我所做的所有研究,我开始意识到长期运行服务的最佳选择是startForeground(),因为它就是为此而设计的,并且系统实际上可以很好地处理您的服务。

【讨论】:

  • @Bam 我有这个确切的问题。但是,我的服务是前台服务,当我的活动关闭时它仍然会被杀死。我将意图初始化参数从上下文 getApplicationContext() 更改为 getBaseContext() 并解决了问题。
  • 我可以在 pendingIntent 中使用 getBaseContext() 吗?
  • 我应该使用startForeground(intent.getIntExtra("notification_Id, 0), builder.build()); 而不是notificationManager.notify(intent.getIntExtra("notification_Id", 0), builder.build()); 吗?我正在使用 NotificationCompat.Builder
  • startForeground() 需要 api 26 有什么解决办法吗?
【解决方案2】:

让你在 Mainifest 中像这样服务

 <service
            android:name=".sys.service.youservice"
            android:exported="true"
        android:process=":ServiceProcess" />

然后您的服务将在名为 ServiceProcess 的其他进程上运行


如果你想让你的服务永不消亡:

  1. onStartCommand() 返回 START_STICKY

  2. onDestroy() -> startself

  3. 创建一个守护程序服务

  4. jin->创建Native Deamon进程,可以在github上找到一些开源项目

  5. startForeground(),有一种方法可以在没有通知的情况下启动Foreground,google一下

【讨论】:

  • 很确定在 onDestroy 中开始自己会被认为与 android 系统作斗争,这是不好的做法。
【解决方案3】:

This 可以帮助你。我可能弄错了,但在我看来,这与在您的 onStartCommand() 方法中返回 START_STICKY 有关。您可以通过返回 START_NOT_STICKY 来避免再次调用该服务。

【讨论】:

  • 实际上,当我退出或关闭应用程序(然后服务重新启动)时,服务停止运行。我不希望服务在我退出/关闭应用程序时暂停/停止;我希望它继续运行。我相信解决方案与在单独的进程上运行服务有关,但我不太确定。
  • 工作正常,谢谢
【解决方案4】:

服务有时相当复杂。

当您从一个活动(或您的进程)启动服务时,该服务本质上是在同一个进程上。

引用开发者说明

关于 Service 类的大部分困惑实际上都围绕着它不是什么:

服务不是一个单独的进程。 Service 对象本身并不意味着它在自己的进程中运行;除非另有说明,否则它会在与其所属的应用程序相同的进程中运行。

服务不是线程。它本身并不是一种脱离主线程工作的方法(以避免 Application Not Responding 错误)。

因此,这意味着,如果用户将应用程序从最近的任务中滑开,它将删除您的进程(这包括您的所有活动等)。 现在,让我们来看三个场景。

第一个服务没有前台通知。

在这种情况下,您的进程与您的服务一起被杀死。

其次服务前台通知

在这种情况下,服务不会被杀死,进程也不会被杀死

第三种场景 如果服务没有前台通知,在应用关闭的情况下它仍然可以继续运行。我们可以通过使服务在不同的进程中运行来做到这一点。 (不过,我听有些人说它可能行不通。留给你自己试试吧

您可以通过包含以下属性在单独的进程中创建服务 在您的清单中。

android:process=":yourService"

android:process="yourService" 进程名称必须以小写开头。

引用开发者笔记

如果分配给此属性的名称以冒号 (':') 开头,则在需要时会创建一个专用于应用程序的新进程,并且服务会在该进程中运行。如果进程名称以 小写 字符开头,则服务将在具有该名称的全局进程中运行,前提是它有权这样做。这允许不同应用程序中的组件共享一个进程,从而减少资源使用。

这是我收集到的,如果有人是专家,如果我错了,请纠正我:)

【讨论】:

    【解决方案5】:

    在 Android O 中,由于 https://developer.android.com/about/versions/oreo/background 的原因,您无法将这些服务用于长时间运行的后台操作。 Jobservice 将是 Jobscheduler 实施的更好选择。

    【讨论】:

    • 什么是Jobservice?
    【解决方案6】:

    主要问题是应用关闭时无法启动服务,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 Activity 这样启动报警管理器,

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

    【讨论】:

      【解决方案7】:

      试试这个,它会让服务在后台运行。

      BackServices.class

      public class BackServices extends Service{
      
          @Override
          public IBinder onBind(Intent arg0) {
              // TODO Auto-generated method stub
              return null;
          }
      
          @Override
         public int onStartCommand(Intent intent, int flags, int startId) {
            // Let it continue running until it is stopped.
            Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
            return START_STICKY;
         }
         @Override
         public void onDestroy() {
            super.onDestroy();
            Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
         }
      }
      

      在你的 MainActivity onCreate 中删除这行代码

      startService(new Intent(getBaseContext(), BackServices.class));
      

      现在服务将继续在后台运行。

      【讨论】:

      • 问题仍然存在:当我从最近的菜单中终止应用程序时,服务会重新启动(再次调用 onStartCommand)。唯一对我有帮助的就是让它成为前台服务。
      【解决方案8】:

      对服务和活动使用相同的进程以及服务中的 START_STICKY 或 START_REDELIVER_INTENT 是能够在应用程序重新启动时重新启动服务的唯一方法,例如,当用户关闭应用程序时会发生这种情况,但当系统出于优化的原因决定关闭它。您不能拥有可以永久运行而不会中断的服务。这是设计使然,智能手机不会长时间运行连续流程。这是因为电池寿命是重中之重。您需要设计您的服务,以便它可以随时停止。

      【讨论】:

        【解决方案9】:

        您必须在您的服务类中添加此代码,以便它处理您的进程被终止时的情况

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

        【讨论】:

          【解决方案10】:

          为什么不使用 IntentService?

          IntentService 在主线程之外打开一个新线程并在那里工作,这样关闭应用程序不会影响它

          请注意,IntentService 运行 onHandleIntent() 并在完成后关闭服务,看看它是否符合您的需求。 http://developer.android.com/reference/android/app/IntentService.html

          【讨论】:

          • 实际上我的要求是要有一个始终运行的后台服务。将服务作为前台服务启动为我解决了这个问题。
          【解决方案11】:

          最好的解决方案是使用android中的sync Adapter来启动服务。创建一个同步适配器并在 onPerformSync 方法中调用它们的启动服务。要创建同步帐户,请参考此链接https://developer.android.com/training/sync-adapters/index.html

          为什么选择 SyncAdapter? Ans: 因为之前你曾经使用你的 App 上下文来启动服务。因此,每当您的应用程序进程被终止时(当您从任务管理器中删除它或操作系统因资源不足而终止它时),您的服务也将被删除。 SyncAdapter 将无法在应用程序线程中工作。所以如果你在其中调用......服务将不再被删除......除非你编写代码来删除它。

          【讨论】:

            【解决方案12】:
            <service android:name=".Service2"
                        android:process="@string/app_name"
                        android:exported="true"
                        android:isolatedProcess="true"
                        />
            

            在您的清单中声明这一点。为您的流程指定一个自定义名称,并使该流程隔离和导出。

            【讨论】:

              【解决方案13】:

              运行 Intent 服务会更容易。在应用程序中创建线程但它仍在应用程序中的服务。

              【讨论】:

                【解决方案14】:

                只需在您的第一个可见活动中覆盖 onDestroy 方法,例如在启动后您有主页并且从启动重定向到主页时您已经完成启动。所以在主页上放上destroy。并以该方法停止服务。

                【讨论】:

                  猜你喜欢
                  • 2015-06-02
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多