StartForeground для IntentService

У меня есть IntentService, и я хочу сделать его закрепленным с текущим уведомлением. Проблема в том, что уведомление появляется и тут же исчезает. Служба продолжает работать. Как мне использовать startForeground() в IntentService?

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);
    Notification notification = new Notification(R.drawable.marker, "Notification service is running",
            System.currentTimeMillis());
    Intent notificationIntent = new Intent(this, DashboardActivity.class);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|
        Intent.FLAG_ACTIVITY_SINGLE_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    notification.setLatestEventInfo(this, "App",
            "Notification service is running", pendingIntent);
    notification.flags|=Notification.FLAG_NO_CLEAR;
    startForeground(1337, notification);
    return START_STICKY;
}

@Override
protected void onHandleIntent(Intent intent) {

    String id = intent.getStringExtra(ID);
    WebSocketConnectConfig config = new WebSocketConnectConfig();
    try {
        config.setUrl(new URI("ws://" + App.NET_ADDRESS
                + "/App/socket?id="+id));
    } catch (URISyntaxException e) {
        e.printStackTrace();
    }
    ws = SimpleSocketFactory.create(config, this);
    ws.open();
}

Спасибо


person Matroska    schedule 29.03.2012    source источник


Ответы (2)


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

Причина, по которой ваш Notification немедленно исчезает, заключается в том, что служба немедленно исчезает.

person CommonsWare    schedule 29.03.2012
comment
Проголосовали против, потому что: скорее всего, это неправильный ответ. Выдержка из документов IntentService: все запросы обрабатываются в одном рабочем потоке -- они могут занимать столько времени, сколько необходимо (и не будут блокировать основной цикл приложения), но только один запрос будет обрабатываться за один раз. время. Ничего не сказано о миллисекундах или около того. developer.android.com/reference/android/app/IntentService.html - person GregoryK; 02.12.2016
comment
Как написано, этот IntentService будет жить около миллисекунды по той простой причине, что код в onHandleIntent() будет выполняться всего за миллисекунду или около того. - person CommonsWare; 17.07.2017
comment
@GregoryK На самом деле ответ правильный, потому что метод onHandleIntent не содержит кода блокировки потока, чтобы предотвратить уничтожение IntentService. - person Arcao; 08.12.2017
comment
этот ответ неверен, согласно документации: This method may take several seconds to complete, so it should only be called from a worker thread. - person sam_k; 25.01.2019

Как указано в документации для IntentService:

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

Итак, я полагаю, проблема в том, что ваша служба не работает после завершения onHandleIntent(). Следовательно, служба останавливается, а уведомление отклоняется. Итак, концепция IntentService, вероятно, не лучший вариант для вашей задачи.


Поскольку заголовок вопроса «StartForeground для IntentService», я хотел бы уточнить некоторые вещи:

Заставить IntentService работать на переднем плане очень просто (см. код ниже), но обязательно нужно учитывать несколько моментов:

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

  • Возможно, вам потребуется сделать так, чтобы ваш сервис мог поддерживать устройство в бодрствующем состоянии (но это уже другая история, которая довольно хорошо освещена в stackoverflow)*

  • Если вы поставили в очередь несколько намерений для своего IntentService, приведенный ниже код в конечном итоге покажет/скроет уведомление. (Таким образом, для вашего случая может быть лучшее решение - поскольку @CommonsWare предлагает расширить Сервис и сделать все самостоятельно, однако хотел бы упомянуть - в javadoc для 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();
        }
    }
}
person GregoryK    schedule 02.12.2016
comment
Общее правило компьютерного программирования: никогда не делайте предположений о ресурсе, который кто-то другой приобрел от вашего имени. Вы не создали фоновый поток, используемый IntentService; следовательно, вы не должны делать никаких предположений о том, как долго вы можете безопасно его использовать. Мы столкнулись с этой самой проблемой с AsyncTask, когда Google изменил правила для execute(), ограничив вас одним потоком для всех задач. Если вы хотите поддерживать тему дольше, чем короткий период, создайте свою собственную тему. Понижение за рекомендацию неудобных методов программирования. - person CommonsWare; 02.12.2016
comment
@CommonsWare Я вижу вашу точку зрения и понимаю ее. В этом есть смысл. На самом деле, я был немного не согласен с утверждением. Как написано, ваш IntentService будет жить около миллисекунды. Я не пытаюсь делать предположения, API java говорит: IntentService — это базовый класс для Сервисов, которые обрабатывают асинхронные запросы (выраженные как намерения) по требованию. Клиенты отправляют запросы через вызовы startService(Intent); служба запускается по мере необходимости, обрабатывает каждое намерение по очереди, используя рабочий поток, и останавливается, когда заканчивается работа. - person GregoryK; 02.12.2016