Усовершенствования реализации WakefulIntentService

Commonsware's WakefulIntentService работает красиво, но есть некоторые вещи, которые я не совсем понимаю. Ниже приведена ядро ​​службы – урезанная версия источника :

class WIS extends IntentService { private static final String NAME = WIS.class.getName() + ".Lock"; private static volatile WakeLock lockStatic = null; synchronized private static PowerManager.WakeLock getLock(Context context) { if (lockStatic == null) { PowerManager mgr = (PowerManager) context .getSystemService(Context.POWER_SERVICE); lockStatic = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NAME); lockStatic.setReferenceCounted(true); } return (lockStatic); } public static void startWIS(Context ctxt, Intent i) { getLock(ctxt.getApplicationContext()).acquire(); ctxt.startService(i); } public WIS(String name) { super(name); setIntentRedelivery(true); } @Override public int onStartCommand(Intent intent, int flags, int startId) { PowerManager.WakeLock lock = getLock(this.getApplicationContext()); if (!lock.isHeld() || (flags & START_FLAG_REDELIVERY) != 0) { // ? lock.acquire(); } super.onStartCommand(intent, flags, startId); return (START_REDELIVER_INTENT); } @Override protected void onHandleIntent(Intent intent) { try { // do your thing } finally { PowerManager.WakeLock lock = getLock(this.getApplicationContext()); if (lock.isHeld()) lock.release(); } } } 

Вопросов

  • Что произойдет, если процесс будет убит сразу после onReceive() нашего приемника сигналов тревоги? То есть, если служба onCreate() (если служба еще не создана) или onStartCommand() никогда не запускается. AFAIK убил процесс, запустив его блокировки. Или это невыполнимый сценарий?
  • С учетом предыдущего следует (flags & START_FLAG_RETRY) ?
  • Почему проверка if (!lock.isHeld()) ?
  • Зачем this.getApplicationContext() ? Разве this недостаточно?

AFAIK убил процесс, запустив его блокировки.

Верный.

Или это невыполнимый сценарий?

Это маловероятно, но, конечно, не невозможно.

С учетом предыдущего следует добавить (флаги & START_FLAG_RETRY)?

Это должно быть охвачено START_FLAG_REDELIVERY . AFAIK, с START_REDELIVER_INTENT , нет RETRY без REDELIVERY . Если у вас есть доказательства обратного, я бы с удовольствием это увидел.

Почему проверка if (! Lock.isHeld ())?

Вызов release() в WakeLock который не удерживается, приводит к исключению. Это просто защитное одеяло, чтобы гарантировать, что мы не забросим ненужное исключение. Теоретически он никогда не понадобится; В теории у меня должны быть волосы.

Зачем нужен this.getApplicationContext ()? Разве этого недостаточно?

Мы создаем WakeLock , который мы держим в статическом элементе данных. Вероятно, getSystemService() не getSystemService() создание Context который вызвал его внутри PowerManager . И даже если бы это произошло, возможно, Context не будет передан в результирующий экземпляр WakeLock . Однако, чтобы быть в безопасности, используя getApplicationContext() , мы получаем WakeLock таким образом, чтобы гарантировать, что единственным Context мы могли бы «протекать», является контекст приложения singleton, который, как одноэлементный, эффективно просочился. 🙂

Извините, у вас недостаточно комментариев для комментариев, но похоже, что у вас есть состояние гонки с двумя проверками, если (удерживается) релиз и если (!). Т.е. сделать ref volatile недостаточно, чтобы охранять вас от рас.

Это составные операторы, вызываемые для разных потоков. Вероятно, вы захотите ввести блок синхронизации для закрытого конечного объекта Object lock = new Object () для этих двух проверок, чтобы они выполнялись атомарно. Очень угловой, но я подумал, что упомянул об этом. Дайте мне знать, если вы не согласны. Благодарю.