Android: остановка службы Foreground, вызывающая сбой приложения - PullRequest
1 голос
/ 29 апреля 2020

Предварительные условия: В рамках требования к моему приложению мне необходимо убедиться, что приложение не будет закрыто (уничтожено) системой Android в фоновом режиме. Для этого я реализовал службу Foreground, хотя я не выполняю никаких реальных процессов в фоновом режиме, просто поддерживаю состояние приложения. Все работает просто отлично, кроме одной вещи, которая мне не совсем понятна, как исправить.

Проблема: Иногда (только один раз, на данный момент) я получаю это исключение:

android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground(): 

Это исключение выдается, когда я пытаюсь остановить службу переднего плана, пока она фактически не запущена.

Итак, мой вопрос - есть ли способ остановить службу переднего плана правильно, чтобы убедиться, что он не работает, прежде чем его остановить? На данный момент я обнаружил, что могу иметь экземпляр stati c для моей службы и сравнивать его со значением null до остановки службы или получить список всех служб, запущенных в данный момент. Но все они выглядят как «обходные» обходные пути.

Вот код: MyForegroundService:

public class ForegroundService extends Service {

public static final int NOTIFICATION_ID = 1;
public static final String CHANNEL_ID = "SessionForegroundServiceChannel";
public static final String ACTION_FOREGROUND_START = "ACTION_FOREGROUND_START";
public static final String ACTION_FOREGROUND_STOP = "ACTION_FOREGROUND_STOP";

public static void startForegroundService(Context context) {
    Intent intent = new Intent(context, ForegroundService.class);
    intent.setAction(ForegroundService.ACTION_FOREGROUND_START);
    ContextCompat.startForegroundService(context, intent);
}

public static void stopForegroundService(Context context) {
    Intent intent = new Intent(context, ForegroundService.class);
    intent.setAction(ForegroundService.ACTION_FOREGROUND_STOP);
    ContextCompat.startForegroundService(context, intent);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (ACTION_FOREGROUND_START.equals(intent.getAction())) {
        createNotificationChannel();
        Intent stopForegroundIntent = new Intent(this, ForegroundServiceBroadcastReceiver.class);
        PendingIntent pendingLogoutIntent = PendingIntent.getBroadcast(this,
                0, stopForegroundIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
                        ? null
                        : getString(R.string.app_short_name))
                .setContentText(getString(R.string.foreground_description))
                .setColor(getResources().getColor(R.color.color))
                .setSmallIcon(R.drawable.ic_notification)
                .addAction(R.drawable.ic_logout, getString(R.string.logout), pendingLogoutIntent)
                .build();
        startForeground(NOTIFICATION_ID, notification);
    } else if (ACTION_FOREGROUND_STOP.equals(intent.getAction())) {
        stopForeground(true);
        stopSelf();
    }
    return START_STICKY;
}

private void createNotificationChannel() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel serviceChannel = new NotificationChannel(
                CHANNEL_ID,
                getString(R.string.app_name),
                NotificationManager.IMPORTANCE_LOW
        );
        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(serviceChannel);
    }
}


@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

}

<service
        android:name=".ui.ForegroundService"
        android:exported="false"
        android:stopWithTask="true"/>

Я также есть BroadcastReceiver и EventBus для прослушивания некоторых событий и остановки переднего плана в зависимости от этих событий.

Не могли бы вы помочь мне, ребята?

1 Ответ

0 голосов
/ 29 апреля 2020

Позвольте мне добавить больше деталей к тому, что прокомментировал @Pawel:

Вы получаете это исключение, если вы не вызываете Service.startForeground в течение 3 секунд после вызова Context.startForegroundService, и это все, что нужно сделать.

Вот как будет выглядеть полное решение:

Когда дело доходит до случая, когда вам нужно остановить службу переднего плана, вам необходимо выполнить следующее (псевдокод):

if (action == START_FOREGROUND) {
    ...
    startForeground(NOTIFICATION_ID, notification);
} else if (action == STOP_FOREGROUND) {
    startForeground(NOTIFICATION_ID, closeNotification); //in case it wasn't started before
    stopForeground(true);
    stopSelf();
}

Даже если это не очевидно, и в любой документации прямо не говорится, что когда вам нужно остановить передний план , вам необходимо запустить передний план перед остановкой это (если оно не было запущено).

Спасибо @Pawel за подсказку.

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