Сбой службы и перезагрузка

Есть несколько вопросов об этом, но я всегда читаю одно и то же: "служба будет убита, если система потребует ресурсов" или "вы не можете создать службу, которая работает вечно, потому что чем больше она работает в фоновом режиме, тем больше восприимчиво к тому, что система убивает его" и т.д.

Проблема, с которой я столкнулся, заключается в следующем: мой сервис работает нормально и, как и ожидалось, если я запустил приложение, то выйду из него, моя служба все еще работает, но когда я убью свое приложение (перейдя в "последние приложения", и запустите его) сервис прекращается. В этот момент, если я перейду к разделу "Настройки → → → , я увижу, что служба перезагружается. Через некоторое время он возвращается и моя служба работает без проблем.

Я google, и я нашел некоторые вещи, которые я мог бы сделать, но сначала посмотрю мой код:

Я запускаю свою службу таким образом (после нажатия кнопки):

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

У меня также есть 3 целых числа, которые я добавил, поэтому у меня есть что-то вроде этого:

final Integer i, i2, i3;
i = 5; //for example
i2 = 10; //for example
i3 = 15; //for example
final Intent intent = new Intent (MainActivity.this, MyService.class);
intent.putExtra("INTEGER1", i);
intent.putExtra("INTEGER2", i2);
intent.putExtra("INTEGER3", i3);
startService(intent);

В MyService у меня есть follooywing:

public class MyService extends Service
{

  AlarmManager am;
  BroadcastReceiver br;
  PendingIntent pi;
  Integer i, i2, i3;

  @Override
  public void onCreate()
  {
    super.onCreate();
    am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    pi = PendingIntent.getBroadcast(this, 0, new Intent("anyany"); 0) //Why those zeros?

    br = new BroadcastReceiver ()
    {
      public void onReceive (Context context, Intent i) {
        new thread(new Runnable()
        {
          public void run()
          {
            //do something
          }
        }).start();
      }
    };
  }

  @Override
  public void onStartCommand(Intent intent, int flags, int startId)
  {
    super.onStartCommand(intent, flags, startId);
    try
    {
      i = intent.getIntExtra("INTENT1", 0) // I don't understant yet why this zero are here
      i2 = intent.getIntExtra("INTENT2", 0)
      i3 = intent.getIntExtra("INTENT3", 0);
    }
    catch(NullPointerException e) {}

    this.registerReceiver(br, new IntentFilter("anyany"));

    new thread(new Runnable()
    {
    public void run()
      {
      am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock. elapsedRealtime() + i*1000, i2*1000, pi);
      }
    }).start();
  return START_REDELIVER_INTENT; //so I can get my Extra even with my Activity closed
}

Мой onDestroy:

@Override
public void onDestroy()
{
  unregisterReceiver(br);
  super.onDestroy();
}

У меня также есть метод onBind() (без @Override), но он возвращает null. Я много google, и я попытался запустить службу на переднем плане, поэтому я сделал это (внутри onStartCommand):

Notification n = new Notification(R.drawable.ic_laucher), getText(R.string.app_name), System.currentTimeMillis());
PendingIntent npi = PendingIntent.getActivity(this, MainActivity.class);
n.setLatestEventInfo(this, getText(R.string.notification_title), getText(R.string.notification_message), npi);
startForeground(3563, n);

Появляется мое уведомление, и когда я нажимаю на него, мое приложение запускается, но проблема с моей службой не была исправлена ​​(я считаю, что она все еще не работает на переднем плане). Уведомление также перезапускается.

Я также удалил Try catch, и я определяю значение для целых чисел (поэтому я не использовал метод getIntExtra()), но ничего не изменилось

После нескольких тестов я попытался увидеть журналы, когда я убью свое приложение. У меня есть следующее сообщение: Планирование перезапуска аварийной службы.

Итак, почему-то мой сервис разбивается, когда моя MainActivity умирает, почему? Цель здесь состоит не в том, чтобы превратить службу в бога, который не может быть убит (я не думаю, что это невозможно вообще, WhatsApp работает в течение 105 часов!), Но не позволяет моей службе не разбиваться после того, как мое приложение умирает.

Я не знаю, поможет ли это, но это то, что я добавляю в свой Manifest.xml

<Activity android:name = ".MyService"/>
<service android:name ="Myservice" android:enabled="true" android: exported="false"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>

Мин. API = 9, целевой API = 17. Размер сервиса при запуске: около 3 МБ.

Надеюсь, что я был ясен и сожалею о своем английском.

PS: весь код работает так, как ожидалось, поэтому, если вы видите, что любая ошибка sintax не удалась, отредактируйте его.

ИЗМЕНИТЬ

Если я добавлю android:isolatedProcess="true" в <service> в AndroidManifest.xml, я получаю эту ошибку в logCat: java.lang.RuntimeException: Unable to create a service in com.mycompany.myapp.myservice: java.lang.SecurityException: Isolated process not allow ed to call getIntentSender

Когда я запускаю свою службу, используя это, MainActivity не показывает никаких erros, только сбой службы.

Ответ 1

Наконец-то я нашел решение! Я удалил AlarmManager из Сервиса, и служба не обналичила больше, но я должен использовать его

Проблема заключается в сбое службы после того, как пользователь запустил приложение из приложения "Недавнее приложение", поэтому я сделал это, чтобы приложение не появлялось в этом окне. Добавьте в свой AndroidManifest.xml следующее дочерние элементы <activity>

android:excludeFromRecents="true"

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

PS: не забудьте установить службу для запуска в отдельном процессе, добавьте следующее в ваш AndroidManifest.xml в качестве дочернего элемента <service>

android:process=":remote"

EDIT - НАСТОЯЩЕЕ РЕШЕНИЕ

После большого количества исследований и исследований (месяцев обучения) я глубоко изучил API-интерфейсы Android и вот что найдено, это ожидаемое поведение, которое наблюдается только при использовании API 16+, изменение на андроиде arquiteture изменило способ, которым PendingIntents транслируются системой, поэтому Google добавил флаг FLAG_RECEIVER_FOREGROUND, вы должны передать этот флаг в намерение, которое вы используете в качестве параметра на PendingIntent.getBroadcast(), вот на пример:

if(Build.VERSION.SDK_INT >= 16)     //The flag we used here was only added at API 16    
    myIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    //use myIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); if you want to add more than one flag to this intent;



PendingIntent pi = PendingIntent.getBroadcast(context, 1, myIntent, 0); // the requestCode must be different from 0, in this case I used 1;

Android версии старше API 16 будут работать, как ожидалось, служба не будет разбиваться, если вы отсканируете приложение на странице Recent Apps.

Ответ 2

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

Вы можете обойти это поведение, создав Service в другом процессе с помощью android: process в тэге <service> в файле Manifest.xml.

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

ИЗМЕНИТЬ 1:

Документация для android: isolProcess говорит:

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

Ответ 3

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

Ваши вопросы из кода:

pi = PendingIntent.getBroadcast(это, 0, новый Intent ( "anyany" ); 0) // Почему эти нули?

Первый нуль, который вы видите, упоминается как requesCode и описывается как не используемый в настоящее время:

requestCode: частный код запроса для отправителя (в настоящее время не используется).

Второй нуль должен быть фактически одним из флагов, указанным (здесь).

i = intent.getIntExtra( "INTENT1", 0)//Я еще не понимаю, почему этот нуль здесь

Метод Intent getIntExtra(String, int) не должен иметь 0 в качестве второго аргумента: он может быть любым целым числом. getIntExtra(String, int) возвращает целое число, соответствующее строковому ключу, который вы предоставляете. В случае, если этот ключ уже не существует (или никогда не был), getIntExtra(String, int) возвращает целое число, которое мы передаем как второй аргумент. Это значение по умолчанию, когда ключ терпит неудачу.