Использование startForeground() с Intent Service
Я пытаюсь сохранить сервис, который реагирует на изменения вкл / выкл экрана. Служба какое-то время прекрасно работала, но потом со временем была бы убита. Сейчас я пытаюсь использовать startForeground(), чтобы поддержать процесс, но он все еще кажется умирающим. Я понимаю, что нет способа сохранить процесс вечным без ошибок, но я чувствую, что, должно быть, я что-то делаю не так, так как добавление startForeground() не добавило дополнительной жизни процессу. Кроме того, в качестве примечания, Logcat жалуется на утечку, поскольку unregisterReceiver() не вызывается (за исключением ручного нажатия кнопки пользователем). Однако, из-за характера того, что я пытаюсь выполнить, получателю нужны бежать, пока явно не скажут остановиться.
Какие-либо предложения?
Соответствующий код:
public class UpdateService extends IntentService {
public UpdateService() {
super(null);
}
@Override
protected void onHandleIntent(Intent intent) {
final int myID = 1234;
Intent notificationintent = new Intent(this, Main.class);
notificationintent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendIntent = PendingIntent.getActivity(this, 0, notificationintent, 0);
Notification notice = new Notification(R.drawable.icon_image, "***********", System.currentTimeMillis());
notice.setLatestEventInfo(this, "*************", "***********", pendIntent);
notice.flags |= Notification.FLAG_NO_CLEAR;
startForeground(myID, notice);
boolean screenOn = intent.getBooleanExtra("screen_state", false);
// Blah Blah Blah......
}
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
3 ответа
(Обновлено) Я полагаю, есть следующие возможные случаи:
1) документация для состояний IntentService:
служба запускается по мере необходимости, обрабатывает каждое намерение по очереди, используя рабочий поток, и останавливается, когда заканчивается его работа.
Таким образом, возможно, что ваш сервис обычно останавливается после onHandleIntent()
закончен (особенно, как вы упомянули, что startForeground() не добавил дополнительной жизни процессу).
2) Вы можете попытаться проверить, может ли это как-то быть связано с переходом устройства в спящий режим (или, может быть, вы запускаете службу по расписанию и отключаете устройство - в этом случае вам может потребоваться приобрести WakeLock)
3) В очень редких случаях система все еще может убить процесс переднего плана - поэтому, если вы делаете много выделений (действительно много) и выполняете какую-то другую работу в onHandleIntent()
(вместо "Бла-бла-бла" в вашем коде) - вы можете столкнуться с этим - но я полагаю, что это не так.
Поскольку вопрос озаглавлен "Использование startForeground() с IntentService" - я бы хотел пояснить это тоже: я не верю, что ничто (архитектура, лучшие практики, платформа Android, документы Java для IntentService) не мешает запускать службу намерений в качестве переднего плана. Конечно, вам необходимо тщательно продумать, как его использовать, и нужен ли вам сервис переднего плана. Некоторые идеи доступны здесь. Пример кода см. Ниже. (Пример кода может в конечном итоге отображать несколько уведомлений, если вы поставили в очередь несколько заданий / намерений в IntentService, поэтому может быть лучшее решение в зависимости от ваших потребностей.)
public class ForegroundService extends IntentService {
private static final String TAG = "FrgrndSrv";
public ForegroundService() {
super(TAG);
}
@Override
protected void onHandleIntent(Intent intent) {
Notification.Builder builder = new Notification.Builder(getBaseContext())
.setSmallIcon(R.drawable.ic_foreground_service)
.setTicker("Your Ticker") // use something from something from R.string
.setContentTitle("Your content title") // use something from something from
.setContentText("Your content text") // use something from something from
.setProgress(0, 0, true); // display indeterminate progress
startForeground(1, builder.build());
try {
doIntesiveWork();
} finally {
stopForeground(true);
}
}
protected void doIntesiveWork() {
// Below should be your logic that takes lots of time
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
IntentService
автоматически выключается, когда onHandleIntent()
завершается. Это выполнить небольшую работу, когда что-то происходит. Как правило, он не должен жить более нескольких секунд.
Я собираюсь предположить, что это связано с тем, что я написал в вашем последнем вопросе в этой области.
Что-то в остальной части вашего приложения будет регистрировать и отменять регистрацию BroadcastReceiver
для экрана вкл / выкл события - видимо, из ваших комментариев это активность. Если то, что вы хотите сделать, когда это происходит, происходит очень-очень быстро (порядка нескольких миллисекунд), просто выполните работу в onReceive()
и покончим с этим.
Если, с другой стороны, у вас больше работы, чем на несколько миллисекунд, вам нужно, чтобы эта работа выполнялась кем-то еще, что может выполнять работу в фоновом потоке. Например, если "что-то в остальной части вашего приложения", которое зарегистрировало BroadcastReceiver
действительно деятельность, активность может просто порождать AsyncTask
делать работу.
Другая возможность заключается в использовании IntentService
, Вы решили пойти по этому пути в своей работе до последнего вопроса. Я не знаю почему. Независимо от IntentService
как AsyncTask
, должен быть недолговечным компонентом - вы посылаете ему команду через startService()
это делает свою работу в onHandleIntent()
и это уходит.
Имея это в виду, давайте поговорим о ваших конкретных точках.
Служба какое-то время прекрасно работала, но потом со временем была бы убита.
Неясно, что, по вашему мнению, означает "убитый". IntentService
автоматически уходит один раз onHandleIntent()
возвращается, и это в идеале должно произойти в течение нескольких секунд.
Сейчас я пытаюсь использовать startForeground(), чтобы поддержать процесс, но он все еще кажется умирающим.
Опять же, неясно, что, по вашему мнению, означает "умирать". Имейте в виду, что само существование IntentService
не останавливает процессор при выключении экрана, и startForeground()
не имеет к этому никакого отношения.
Кроме того, в качестве примечания, Logcat жалуется на утечку, так как unregisterReceiver() не вызывается (за исключением ручного нажатия кнопки пользователем).
Вам также необходимо отменить регистрацию получателя до того, как пользователь завершит работу. Обычно это хорошая идея, чтобы позвонить registerReceiver()
в onResume()
а также unregisterReceiver()
в onPause()
,
Если памяти мало, и вы потребляете слишком много памяти и слишком долго сидите на заднем плане, тогда ActivityManager убьет вас.