12

На Android у меня есть ActivityFirstActivity, который запускает Service по имени MyService, чтобы сделать сетевые материалы в фоновом режиме. Activity и Service постоянно взаимодействуют друг с другом, вызывая методы.Деятельность с длительным обслуживанием в фоновом режиме, которое не будет убито

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

Другими словами, Service должен работать до тех пор, как один из двух Activity с управлением, и он не должен останавливаться, когда пользователь переходит между двумя Activity с.

Один из Activity s всегда будет находиться на переднем плане, и за это время служба (оптимально) не будет убита. Я думаю, что это не должно быть проблемой, потому что один из этих двух Activity s всегда активен, и поэтому Android знает, что услуга важна, а не то, что нужно убить.

(Если бы не было никакого способа предотвратить Android от убийства и повторного создания службы время от времени, я должен был бы способ восстановления полного состояния службы грациозно.)

Резюмируя , у Service должна быть такая же продолжительность жизни, как и у двух Activity s "в сочетании". Он должен начинаться с первого из них и останавливаться не раньше, чем обе они были уничтожены.

. Правильно ли указан следующий код и цели?

public class MyService extends Service { 

    public class LocalBinder extends Binder { 
     public MyService getService() { 
      return MyService.this; 
     } 
    } 

    ... 

} 

public class FirstActivity extends Activity { 

    private MyService mMyService; 

    private ServiceConnection mMainServiceConnection = new ServiceConnection() { 

     @Override 
     public void onServiceConnected(ComponentName className, IBinder service) { 
      MyService mainService = ((LocalBinder) service).getService(); 
      mMyService = mainService; 
      mMyService.setCallback(FirstActivity.this); 
     } 

     @Override 
     public void onServiceDisconnected(ComponentName className) { 
      mMyService = null; 
     } 
    }; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     ... 
     startService(new Intent(FirstActivity.this, MyService.class)); 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     bindService(new Intent(FirstActivity.this, MyService.class), mMainServiceConnection, Context.BIND_AUTO_CREATE); 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
     if (mMainServiceConnection != null) { 
      unbindService(mMainServiceConnection); 
     } 

     if (mMyService != null) { 
      mMyService.setCallback(null); 
     } 

     if (!isUserMovingToSecondActivity) { 
      stopService(new Intent(FirstActivity.this, MyService.class)); 
     } 
    } 

    @Override 
    public void onBackPressed() { 
     stopService(new Intent(FirstActivity.this, MyService.class)); 
     super.onBackPressed(); 
    } 

    ... 

} 

public class SecondActivity extends Activity { 

    private MyService mMyService; 

    private ServiceConnection mMainServiceConnection = new ServiceConnection() { 

     @Override 
     public void onServiceConnected(ComponentName className, IBinder service) { 
      MyService mainService = ((LocalBinder) service).getService(); 
      mMyService = mainService; 
      mMyService.setCallback(SecondActivity.this); 
     } 

     @Override 
     public void onServiceDisconnected(ComponentName className) { 
      mMyService = null; 
     } 
    }; 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     bindService(new Intent(SecondActivity.this, MyService.class), mMainServiceConnection, Context.BIND_AUTO_CREATE); 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
     if (mMainServiceConnection != null) { 
      unbindService(mMainServiceConnection); 
     } 
    } 

    @Override 
    protected void onDestroy() { 
     ... 
     stopService(new Intent(SecondActivity.this, MyService.class)); 
    } 

    ... 

} 

Это лучший способ гарантировать длительный сервис в фоне Activity с, что не будет убит или воссозданной?

Что относительно Context.BIND_AUTO_CREATE? Правильно ли здесь установить этот флаг? Что относительно Context.BIND_ADJUST_WITH_ACTIVITY и Context.BIND_WAIVE_PRIORITY - мне это нужно?

+0

Вы пробовали этот код или спрашиваете, прежде чем пытаться? Если вы попытались, вы получили какие-либо ошибки? Разве это не так, как вы ожидали? У нас будет гораздо более продуктивная дискуссия и более полезный ответ для сообщества и самого себя, если вы действительно попробуете его, а затем попросите у нас решить конкретную проблему у вас есть – DallaRosa

+0

@ DallaRosa Да, конечно, я пробовал это.Это общий вопрос о том, как создать класс обслуживания и соответствующие классы «Активность», чтобы служба длилась как можно дольше и не была убита. Пользователи сообщили, что функции, предоставляемые этой службой, перестают быть доступными в одном из классов «Активность» время от времени. И мне (а) трудно отлаживать, когда система может убить эту услугу, и (б) хотел бы узнать о некоторых передовых методах или улучшениях, которые должны применяться к этой службе для четко определенных целей и требований. – caw

+0

Я вижу много вопросов в вашем управлении 'Сервис'. Вам нужно остановить его только тогда, когда первая «активность» будет уничтожена или зависит от привязки и правильной работы. В Начальных книгах Android есть некоторые общие инструкции: https://books.google.com.pk/books?id=mRGrCQbqHkoC&pg=PA399 – corsair992

ответ

7

(Большое спасибо @ corsair992 за его полезные указатели!)


Если деятельность всегда вызываются в таком порядке (т.е. FirstActivity начинает SecondActivity, и никогда наоборот, то . вы должны, в основном, попытка «привязать» жизненный цикл сервиса в жизненном цикле FirstActivity «s

в целом (см предостережений позже), это означает, что:

  • Звоните по номеру startService() в FirstActivity.onCreate().
  • Звоните по номеру stopService() в FirstActivity.onDestroy().
  • Позвоните по bindService()/unbindService() методам обеих Деяний (чтобы получить доступ к объекту Binder и иметь возможность называть методы на нем).

Сервис начал этот путь будет жив до тех пор, пока stopService() называется и развязывает каждый клиент, см Managing the Lifecycle of a Service:

Эти два пути не полностью разделены. То есть вы можете привязать к службе , которая уже была запущена с помощью startService(). (...) В таких случаях stopService() или stopSelf() фактически не останавливает обслуживание до тех пор, пока все клиенты не отвяжут.

и:

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

С помощью этой базовой стратегии Служба будет работать до тех пор, пока не будет FirstActivity (т. Е. Она не будет уничтожена). Тем не менее, остается важный момент: в случае изменения конфигурации (например, вращения экрана), которое не обрабатывается явно, это приведет к перезагрузке активности, и служба будет уничтожена (поскольку мы вызываем stopService() в onDestroy()) ,

Чтобы предотвратить это, вы можете проверить isChangingConfigurations() до фактического прекращения службы (так как onDestroy() обратного вызова происходит по этой причине означает, что, хотя этот конкретный экземпляр деятельности разрушается, он будет воссоздан после этого.

Таким образом, полное решение было бы что-то вроде:

public class FirstActivity extends Activity 
{ 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     startService(new Intent(this, MyService.class)); 
    } 

    private ServiceConnection mServiceConnection = new ServiceConnection() { ... } 

    @Override 
    protected void onStart() { 
     super.onStart(); 
     bindService(new Intent(this, MyService.class), mServiceConnection, Context.BIND_AUTO_CREATE); 
    } 

    @Override 
    protected void onStop() { 
     unbindService(mServiceConnection); 
     super.onStop(); 
    } 

    @Override 
    protected void onDestroy() { 
     if (!isChangingConfigurations()) 
      stopService(new Intent(this, MyService.class)); 

     super.onDestroy(); 
    } 

Хотя SecondActivity бы только реализовать onStart()/onStop() методы (в том же ва у).


Несколько замечаний о конкретной реализации:

  • Это не нужно переопределить onBackPressed(), так как если деятельность уничтожается необходимые методы жизненного цикла будут называться (плюс, это может быть закончено без нажатие кнопки «Назад», например, при вызове на нем finish()).
  • Прекращение обслуживания в onDestroy() вместо onPause() избавляет вас от необходимости проверять наличие isUserMovingToSecondActivity.
+0

Спасибо! (1) Для нашей цели вы можете использовать 'onStart()'/'onStop()' и 'onResume()'/'onPause()' взаимозаменяемо, не так ли? В противном случае вторая пара методов кажется превосходной, потому что она * гарантирована *, чтобы быть вызванной, в отличие от первой пары, правильно? (2) Действительно ли проверка для 'isChangingConfigurations()' действительно имеет значение? Если 'FirstActivity' уничтожен, мы все равно теряем членную переменную' mMyService', и 'onCreate (...)' и 'onStart()' снова вызываются (что также означает, что вы могли бы дважды привязать). И в «SecondActivity» мы теряем соединение в любом случае. – caw

+1

@ MarcoW. (1) 'onStop()' может не прибыть, а AFAIK, только если приложение будет убито, и в этом случае служба тоже будет. (2) Вы потеряете локальную привязку, но служба фактически не уничтожается, а затем воссоздается, когда вы снова связываете (так что, если у вас есть какой-то текущий процесс, он все равно будет «там»). Однако это будет, если вы вызовете 'stopService()'. Я предположил, что вы хотите сохранить состояние обслуживания при вращении. – matiash

+0

Что касается (2), когда 'onStop()' вызывается в 'SecondActivity',' Service', вероятно, убит (потому что никакая 'Activity' больше не связывается с ним и все' Activity ', которые вызывают' startService (...) 'вызывают' stopService (...) '), прежде чем вы сможете повторно связать в' onStart() 'после изменения конфигурации. Я ошибаюсь? – caw

 Смежные вопросы

  • Нет связанных вопросов^_^