Android: понимание использования одного IntentService с несколькими действиями

У меня проблема с тем, что намерение не доставляется IntentService в рамках определенного потока действий: это сценарий:

  1. Рассмотрим 3 действия, Home, B и C. C имеет 2 фрагмента CF1 и CF2.
  2. B, CF1 и CF2 используют один и тот же класс IntentService, но с разными действиями.
  3. IntentService запускается с использованием startService(Intent). (getActivity().startService(Intent) для фрагментов)
  4. Когда IntentService запускается, я убеждаюсь, что он останавливается с помощью stopService(intent), если он работает в Activity/Fragment onStop().
  5. Если поток активности Home -> C -> CF1 -> CF2, все работает.
  6. Если поток действий Home -> B -> C -> CF1 -> CF2, то onHandleIntent никогда не вызывается после startService(Intent) из CF2. Намерения B и CF1 обрабатываются. Для отладки я попытался дождаться завершения IntentService в действии B, а затем перейти к CF1 -> CF2, но все та же проблема. У CF1 никогда не бывает проблем с запуском той же службы намерений. Когда я попытался создать новый класс IntentService для CF2, это сработало.

Насколько я понимаю, у IntentService есть очередь для намерений. Если служба запускается в первый раз, вызывается onStartCommand (который мы не должны обрабатывать для IntentService). Если служба уже запущена, onHandleIntent вызывается для каждого последующего вызова startService.

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

AndroidManifest.xml

<service android:name=".service.ExampleIntentService" />

Действие Б

@Override
public void onCreate(Bundle savedInstanceState)
{
       .......
       intent = new Intent(getApplicationContext(), ExampleIntentService.class);
       intent.setAction(StringConstants.ACTION_B);
       serviceRunning = true; //set to false in onReceiveResult 
       startService(intent);
}

@Override
public void onStop()
{
      if(serviceRunning && intent != null)
          stopService(intent)
}

Фрагмент CF1

@Override
public void onResume()
{
    super.onResume();

    intent = new Intent(getActivity(), ExampleIntentService.class);
    intent.setAction(StringConstants.ACTION_CF1);
    serviceRunning = true; //set to false in onReceiveResult 
    startService(intent);
}

@Override
public void onStop()
{
      if(serviceRunning && intent != null)
          stopService(intent)
}

Код точно такой же для фрагмента, CF2


person Prasanna    schedule 17.02.2013    source источник
comment
IntentService не ставит намерения в очередь. startService вызывается для каждого входящего намерения; все вызовы ставятся в очередь в потоке Looper, локальном для службы. Остановка службы, когда она ничего не делает, является хорошей практикой, это всего лишь оптимизация. Я предлагаю вам прекратить это делать, пока ваше приложение не заработает должным образом.   -  person G. Blake Meike    schedule 17.02.2013
comment
@G.BlakeMeike G.BlakeMeike Я не понимаю разницы между «не ставит в очередь намерения» и «вызовы ставятся в очередь в потоке Looper, локальном для службы». Я попробую вызвать stopService и посмотреть. Но не лучше ли было бы просто создать отдельный сервис намерений? Я знаю, что это сработает. edit: Также я не уверен, почему я не вижу той же проблемы с фрагментом CF1.   -  person Prasanna    schedule 17.02.2013
comment
Разница в том, что намерения всегда доставляются в IntentService.startService. Метод startService помещает вызовы в локальную очередь, из которой они удаляются из очереди другим потоком и доставляются как вызовы onHandleIntent. Все они. См. ответ Марка ниже: прекратите вызывать stopService.   -  person G. Blake Meike    schedule 17.02.2013


Ответы (1)


Насколько я понимаю... Если служба запускается впервые, вызывается onStartCommand (который мы не должны обрабатывать для IntentService). Если служба уже запущена, onHandleIntent вызывается для каждого последующего вызова startService.

onStartCommand() вызывается для каждого startService() вызова. onHandleIntent() вызывается для каждого startService() вызова IntentService, если вы не делаете что-то в onStartCommand() для изменения нормального поведения.

IntentService запускается с помощью startService(Intent).

Вы отправляете команды IntentService с помощью startService().

Везде, где запускается IntentService, я убеждаюсь, что он останавливается с помощью stopService(intent)

Это исключительно плохая идея. IntentService остановится, когда все вызовы startService() будут обработаны, как указано в документации:

IntentService получит намерения, запустит рабочий поток и при необходимости остановит службу.

person CommonsWare    schedule 17.02.2013
comment
Как и вы сказали @G.BlakeMeike, я попытался удалить stopService, и это сработало. Но опять же, я не уверен, какой правильный подход, когда пользователь уходит от активности, в которой запущен IntentService. Вы говорите, что это плохая идея, разве мы не должны просто остановить службу, если пользователь уходит от активности? - person Prasanna; 17.02.2013
comment
@Prasanna: Смысл использования IntentService заключается в том, что вы хотите продолжать работу, если пользователь отходит от действия. Если вы этого не хотите, не используйте IntentService — просто используйте поток. - person CommonsWare; 17.02.2013