83

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

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

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

4

14 回答 14

48

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

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

于 2013-06-22T23:07:26.017 回答
13

让你在 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,谷歌一下

于 2016-07-21T06:50:20.323 回答
12

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

于 2013-05-20T13:55:28.383 回答
11

服务有时相当复杂。

当您从活动(或您的流程)启动服务时,该服务基本上位于同一流程上。

引用开发者笔记

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

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

服务不是线程。它本身并不是一种脱离主线程工作的方法(以避免应用程序无响应错误)。

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

首先,服务没有前台通知。

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

第二个服务前台通知的

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

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

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

android:process=":yourService"

或者

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

引用开发者笔记

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

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

于 2017-08-31T19:10:56.527 回答
5

主要问题是应用程序关闭时无法启动服务,android 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;
    }
}

当打开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");
    }
}
于 2017-01-17T07:10:00.440 回答
5

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

于 2019-02-07T06:52:27.267 回答
1

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

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

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

于 2014-12-03T12:01:42.147 回答
1

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

于 2017-08-06T09:57:51.487 回答
1

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

 @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);
    }
于 2017-10-03T07:45:47.553 回答
0

为什么不使用 IntentService?

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

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

于 2015-05-31T09:02:36.797 回答
0

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

于 2017-11-14T22:52:05.753 回答
0

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

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

于 2017-07-06T08:01:37.467 回答
0
<service android:name=".Service2"
            android:process="@string/app_name"
            android:exported="true"
            android:isolatedProcess="true"
            />

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

于 2017-07-07T10:37:38.037 回答
-6

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

于 2016-01-18T10:30:43.870 回答