Не удается сохранить поддержку Android после закрытия приложения.

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

Храните сервис определения местоположения живым, когда приложение закрыто.

Служба Android останавливается, когда приложение закрыто

Android: сохранить сервис, когда приложение убито

это может быть выполнено с помощью IntentServices или Service.START_STICKY

Тем не менее, я пробовал оба типа услуг без успеха. Другими словами, мои сервисы убиваются, когда приложение закрывается пользователем. Может ли кто-нибудь указать, можно ли это сделать и как? Вот что я пробовал без успеха:

С IntentService:

public class MyIntentService extends IntentService {
    private final int mPollingTimeMS = 500;
    private int mInitializationPollingCount = 0;
    private Thread mPollThread;
    public MyIntentService() {
        super("MyIntentService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        mPollThread = new Thread() {
            public void run() {
                while (true) {
                    try {
                        Log.e(Constants.Engine.LOGGER_TAG_DEV,
                                "SDK Service Running: " +
                                        mInitializationPollingCount * mPollingTimeMS +
                                        "ms have elapsed");
                        mInitializationPollingCount++;
                        sleep(mPollingTimeMS);

                    } catch (Exception e) {
                        StackTraceElement trace = new Exception().getStackTrace()[0];
                        Logger.e(Constants.Engine.LOGGER_TAG_APP, "[Exception:" + e.toString() + "]" +
                                trace.getClassName() + "->" + trace.getMethodName() + ":" + trace.getLineNumber());
                    }
                }
            }
        };
        mPollThread.start();
    }
}

и с услугами:

public class MyService extends Service {
    public MyService() {
    }
    private final int mPollingTimeMS = 500;
    private int mInitializationPollingCount = 0;
    private Thread mPollThread;
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mPollThread = new Thread() {
            public void run() {
                while (true) {
                    try {
                        Log.e(Constants.Engine.LOGGER_TAG_DEV,
                                "SDK Service Running: " +
                                        mInitializationPollingCount * mPollingTimeMS +
                                        "ms have elapsed");
                        mInitializationPollingCount++;
                        sleep(mPollingTimeMS);

                    } catch (Exception e) {
                        StackTraceElement trace = new Exception().getStackTrace()[0];
                        Logger.e(Constants.Engine.LOGGER_TAG_APP, "[Exception:" + e.toString() + "]" +
                                trace.getClassName() + "->" + trace.getMethodName() + ":" + trace.getLineNumber());
                    }
                }
            }
        };
        mPollThread.start();
        return Service.START_STICKY;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // I tried to return null here, but this
        // service gets killed no matter what.
        return null;
    }
}

и вот манифест:

    <service
        android:name=".mycompany.MyService"
        android:enabled="true"
        android:exported="true"
        android:process=":process1">
    </service>
    <service
        android:name=".mycompany.MyIntentService"
        android:process=":process2"
        android:exported="false">
    </service>

Я добавлю, что закрываю тестовое приложение не с помощью кнопки "закрыть", а с помощью диспетчера приложений Android OS. См. Рисунок ниже

enter image description here

Наконец, активность водителя (не так много)

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent1 = new Intent(getBaseContext(), MyService.class);
        startService(intent1);
        Intent intent2 = new Intent(getBaseContext(), MyIntentService.class);
        startService(intent2);

    }
}

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

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    showNotification();
...etc..

private void showNotification() {
    Intent notificationIntent = new Intent(this, MainActivity.class);
    notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
            notificationIntent, 0);
    int iconId = R.mipmap.ic_launcher;
    int uniqueCode = new Random().nextInt(Integer.MAX_VALUE);
    Notification notification = new NotificationCompat.Builder(this)
            .setSmallIcon(iconId)
            .setContentText("Context Text")
            .setContentIntent(pendingIntent).build();
    startForeground(uniqueCode, notification);
}

Ответы

Ответ 1

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

public class MyService extends Service {
static final int NOTIFICATION_ID = 543;

public static boolean isServiceRunning = false;

@Override
public void onCreate() {
    super.onCreate();
    startServiceWithNotification();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (intent != null && intent.getAction().equals(C.ACTION_START_SERVICE)) {
        startServiceWithNotification();
    }
    else stopMyService();
    return START_STICKY;
}

// In case the service is deleted or crashes some how
@Override
public void onDestroy() {
    isServiceRunning = false;
    super.onDestroy();
}

@Override
public IBinder onBind(Intent intent) {
    // Used only in case of bound services.
    return null;
}


void startServiceWithNotification() {
    if (isServiceRunning) return;
    isServiceRunning = true;

    Intent notificationIntent = new Intent(getApplicationContext(), MyActivity.class);
    notificationIntent.setAction(C.ACTION_MAIN);  // A string containing the action name
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    PendingIntent contentPendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

    Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.my_icon);

    Notification notification = new NotificationCompat.Builder(this)
            .setContentTitle(getResources().getString(R.string.app_name))
            .setTicker(getResources().getString(R.string.app_name))
            .setContentText(getResources().getString(R.string.my_string))
            .setSmallIcon(R.drawable.my_icon)
            .setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
            .setContentIntent(contentPendingIntent)
            .setOngoing(true)
//                .setDeleteIntent(contentPendingIntent)  // if needed
            .build();
    notification.flags = notification.flags | Notification.FLAG_NO_CLEAR;     // NO_CLEAR makes the notification stay when the user performs a "delete all" command
    startForeground(NOTIFICATION_ID, notification);
}

void stopMyService() {
    stopForeground(true);
    stopSelf();
    isServiceRunning = false;
}
}

Затем я запускаю его с помощью

    Intent startIntent = new Intent(getApplicationContext(), MyService.class);
    startIntent.setAction(C.ACTION_START_SERVICE);
    startService(startIntent);

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

Ответ 2

IntentService

Использование IntentService, вероятно, не лучший подход. По умолчанию IntentService останавливается после того, как onHandleIntent(Intent) возвращается и не остается никакой работы (т. onHandleIntent(Intent) Очередь запросов пуста). Это объясняется в официальных документах IntentService:

Когда все запросы обработаны, IntentService останавливается, поэтому вам не следует вызывать stopSelf().

В вашем случае onHandleIntent(Intent) создает поток, но сразу же возвращает его, что останавливает его сам.

Сервис + startForeground()

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

  1. Сделайте, чтобы onStartCommand() возвращал START_STICKY.
  2. Вызовите метод, чтобы показать уведомление прямо в onCreate().
  3. Запустите службу в отдельном процессе (используя android:process=":something").

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

Ответ 3

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

Ответ 4

Если ни один из приведенных выше ответов не работает, возможно, это проблема конкретного производителя. Например, некоторые телефоны MI убивают службу переднего плана, когда пользователь убивает приложение через диспетчер задач.

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

Надеюсь, поможет!