Служба Android Останавливается, Когда Приложение Закрыто


Я запускаю сервис из моей основной деятельности Android следующим образом:

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

Когда я закрываю страницу активности, проводя ее из списка последних приложений, служба перестает работать и перезапускается через некоторое время. Я не могу использовать постоянные службы с уведомлениями из-за требований к приложению. Как сделать так, чтобы служба не перезапускалась и не выключалась, а просто продолжала работать при выходе из приложения?

13 61

13 ответов:

Я нахожусь в той же ситуации, до сих пор я узнал, когда приложение закрыто, сервис закрывается также потому, что они находятся в одном потоке, поэтому сервис должен быть в другом потоке, чтобы он не был закрыт, посмотрите на это и посмотрите, чтобы сохранить службу живой с alarm manager вот пример http://www.vogella.com/articles/AndroidServices/article.html таким образом, ваш сервис не будет отображаться в уведомлении.

Наконец, после всех исследований, которые я сделал, я прихожу к поймите, что лучший выбор для длительного обслуживания-это startForeground(), потому что она создана для этого, и система действительно хорошо справляется с вашим сервисом.

Это может вам помочь. Я могу ошибаться, но мне кажется, что это связано с возвращением START_STICKY в вашем методе onStartCommand(). Вы можете избежать повторного вызова службы, вернув вместо этого START_NOT_STICKY.

Сделать вас обслуживание как это в вашем Манифеста

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

Тогда ваша служба будет работать на другом процессе с именем ServiceProcess


Если вы хотите, чтобы ваша служба никогда не умирала:

  1. OnStartCommand () возвращает START_STICKY

  2. OnDestroy () - > startself

  3. Создайте службу Deamon

  4. Jin - > создайте собственный процесс Deamon, вы можете найти некоторые проекты с открытым исходным кодом на github

  5. Начальный план() , есть способ начать переднюю часть без уведомления, google it

Услуги иногда довольно сложны.

Когда вы запускаете службу из действия (или вашего процесса), служба по существу находится в том же самом процессе.

Цитирование из заметок разработчика

Большая путаница в отношении класса обслуживания на самом деле вращается вокруг того, чем он не является:

Служба-это не отдельный процесс. Сам объект сервиса не подразумевает, что он выполняется в собственном процессе; если не указано иное, он выполняется в том же процессе, что и объект сервиса. приложение, частью которого он является.

Служба-это не поток. Это не средство само по себе делать работу вне основного потока (чтобы избежать ошибок приложения, не отвечающего на запросы).

Итак, это означает, что если пользователь уберет приложение от недавних задач, он удалит ваш процесс (это включает все ваши действия и т. д.). Теперь давайте рассмотрим три сценария.

Первый где служба не имеет переднего плана уведомление.

В этом случае ваш процесс будет убит вместе с вашим сервисом.

второе где служба имеет уведомление переднего плана

В этом случае служба не убита, как и процесс

третий сценарий Если служба не имеет уведомления переднего плана, она все еще может продолжать работать, если приложение закрыто. Мы можем сделать это, заставив службу работать в другом процессе. (Однако, Я слышал, что некоторые люди говорят, что это может не сработать. предоставлено вам самому попробовать )

Вы можете создать сервис в отдельном процессе, включив следующий атрибут в вашем манифесте.

Android: process=": yourService "

Или

Android: process= "yourService" имя процесса должно начинаться со строчной буквы.

Цитирование из заметок разработчика

Если имя, присвоенное этому атрибуту, начинается с двоеточия ( ' :'), то процесс, закрытый для приложения, создается, когда это необходимо, и служба запускается в этом процессе. Если имя процесса начинается с символа в нижнем регистре , служба будет работать в глобальном процессе с таким именем, при условии, что у нее есть на это разрешение. Это позволяет компонентам в различных приложениях совместно использовать процесс, уменьшая потребление ресурсов.

Это то, что я собрал, если кто-то является экспертом, пожалуйста, поправьте меня, если я ошибаюсь :)

Попробуйте это, он будет держать службу работает в фоновом режиме.

Бэксервисы.класс

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

В вашей основной активности onCreate отбросьте эту строку кода

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

Теперь служба будет работать в фоновом режиме.

Основная проблема в неспособности запустить службу, когда приложение закрыто, ОС android (в некоторых ОС ) убьет службу для оптимизации ресурсов, если вы не можете перезапустить службу, то вызовите аварийную кормушку, чтобы запустить ресивер, как это,вот весь код, этот код будет поддерживать жизнь службы ur.

Манифест есть,

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

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

Это потребует ресивер и ресивер-это,

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

И этот Аларам reciver звонит один раз, когда приложение для android открыто и когда приложение closed.SO служба такова,

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

Лучшее решение-использовать адаптер синхронизации в android для запуска службы. Создайте адаптер синхронизации и вызовите службу запуска их.. внутри метода onPerformSync. чтобы создать учетную запись синхронизации, перейдите по этой ссылке https://developer.android.com/training/sync-adapters/index.html

Почему Именно SyncAdapter? Ans: потому что раньше вы запускали службу, используя контекст приложения. поэтому всякий раз, когда ваш процесс приложения будет убит (когда вы удалите его из Диспетчера задач или ОС убьет его из-за отсутствия ресурсы) в это время ваш сервис также будет удален. SyncAdapter не будет работать в потоке приложения.. так что если вы позвоните в него.. служба больше не будет удалена.. если только вы не напишете код, чтобы удалить его.

Использование одного и того же процесса для службы и действия и START_STICKY или START_REDELIVER_INTENT в службе-это единственный способ перезапустить службу, когда приложение перезапускается, что происходит, например, когда пользователь закрывает приложение, а также когда система решает закрыть его по причинам оптимизации. Вы не можете иметь службу, которая будет работать постоянно без каких-либо перерывов. Это по дизайну, смартфоны не предназначены для запуска непрерывных процессов в течение длительного времени период времени. Это связано с тем, что время автономной работы является наивысшим приоритетом. Вы должны спроектировать свой сервис так, чтобы он был остановлен в любой момент.

Почему бы не использовать IntentService?

IntentService открывает новый поток отдельно от основного потока и работает там, таким образом, закрытие приложения не повлияет на него

Имейте в виду, что IntentService запускает onHandleIntent (), и когда это сделано, служба закрывается, посмотрите, соответствует ли она вашим потребностям. http://developer.android.com/reference/android/app/IntentService.html

<service android:name=".Service2"
            android:process="@string/app_name"
            android:exported="true"
            android:isolatedProcess="true"
            />
Объявите об этом в своем манифесте. Дайте процессу собственное имя и сделайте его изолированным и экспортированным .

Вы должны добавить этот код в свой класс обслуживания, чтобы он обрабатывал случай, когда ваш процесс убивается

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

Запустить службу intent будет проще. Служба в создании потока в приложении, но он все еще находится в приложении.

Просто переопределите метод onDestroy в вашем первом видимом действии, например, после splash у вас есть домашняя страница, и при перенаправлении с splash на домашнюю страницу вы уже закончили splash. так что поставьте на destroy в главной странице. и остановите обслуживание в этом методе.