Как календарь Google или Instagram делают свои приложения все время и работают даже после принудительной остановки
Похоже, принудительная остановка должна препятствовать запуску приложения и даже отключить все приложения. Однако я обнаружил, что уведомление в Календаре Google по-прежнему отображается даже после остановки принудительной остановки, и я все время смотрю приложение Instagram, даже когда я его убиваю, он просто перезагружается автоматически, и он снова там.
Итак, каков способ заставить приложение работать постоянно? Я делаю приложение с напоминаниями и должен показывать уведомления в определенное время, независимо от того, как приложение ранее было закрыто раньше.
Ответы
Ответ 1
Если вы запускаете службу в классе приложения, чем ваша служба будет работать, даже если пользователь прекратит или остановит работу с диспетчером задач, он снова запустится.
Чтобы создать службу специально в студии Android Щелкните правой кнопкой мыши приложение из Project Explorer, а затем Создать > Сервиs > Сервис
Создайте сервис:
public class ServiceName extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// do your jobs here
return super.onStartCommand(intent, flags, startId);
}
}
Теперь создайте класс приложения и запустите службу в классе приложений
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
startService(new Intent(this, ServiceName.class));
}
}
Ответ 2
Я вижу два варианта.
Сначала нужно обработать любое исключение через Thread.setDefaultUncaughtExceptionHandler()
, который отправляется с Java, а не с Android SDK.
Чтобы быть кратким, вы производите свой собственный Application
класс UncaughtExceptionHandler
и регистрируете его как слушателя для любого исключения в приложении. Как только произойдет некоторая авария, этот обратный вызов будет запущен из того места, где вы можете отложить выполнение задания в ближайшем будущем (например, spawn AlarmManager
, чтобы снова запустить приложение за 50 мс).
Второй вариант заключается в том, что вы можете запускать свои компоненты в разных процессах. Из docs:
Android: процесс
Название процесса, в котором должна выполняться служба. Обычно все компоненты приложения запускаются в процессе по умолчанию, созданном для приложения. Он имеет то же имя, что и пакет приложений. Атрибут процесса элемента может устанавливать разные значения по умолчанию для всех компонентов. Но компонент может переопределить значение по умолчанию со своим собственным атрибутом process, что позволяет распространять ваше приложение на несколько процессов.
Авария, которая происходит при разных процессах, не приведет к сбою вашего пользовательского интерфейса.
Ответ 3
Хорошо для стартеров у них есть система планировщика заданий, которая планирует выполнение заданий для выполнения, эти задания можно остановить, начать или возобновить. Они реализуют механизм обнаружения сбоя, думают java- script, где, если приложение сработает, его можно перезапустить (nodemon или forever), в android есть службы, которые могут быть запущены или возобновлены. Это поведение специальной службы перезапускается разбитые службы.
START_REDELIVER_INTENT - сообщает системе перезапустить службу после сбоя, а также повторно обновить намерения, которые присутствовали во время сбоя.
В выпуске Android 5.0 Lollipop (API 21) представлен API планировщика заданий через класс JobScheduler. Этот API позволяет выполнять пакетные задания, когда у устройства больше доступных ресурсов. В общем, этот API можно использовать для планирования всего, что не критично для пользователя.
Вы также можете смешивать сигналы тревоги, широковещательные приемники и потоки в сочетании с реактивным программированием для выполнения задания. Агрегаты (основанные на классе AlarmManager) дают вам возможность выполнять временные операции за пределами срока службы вашего приложения. Например, вы можете использовать будильник для запуска долговременной операции, например, запуск службы один раз в день для загрузки прогноза погоды.
Вы можете прикреплять наблюдаемые к определенным задачам, выполняющим определенные операции. Вы можете реализовать асинхронные операции ввода-вывода, вычислительные операции или даже "бесконечные" потоки данных, создав собственный наблюдаемый.
Ответ 4
Просто добавьте с ответом Сагара Дамани. Для выполнения длительной операции в фоновом режиме требуется служебный вызов, но они также выполняются в процессах со спасителем. Когда вы объявляете службу или активность в файле androidMenifes.xml, также добавляйте атрибут android: process = "". Поэтому он всегда будет постоянным, если пользователь убивает/принудительно останавливает действие.
Ответ 5
Основываясь на моих ограниченных знаниях, вам нужно использовать AlarmManager
, WakefulBroadcastReceiver
и создать Service
или IntentService
для всех этих фоновых задач. Подробнее об этом здесь. У меня есть сервис, который я использовал для своего приложения для обмена сообщениями Firebase, и он отлично работает даже после того, как пользователь убил приложение. В моем случае я подключаюсь к Firebase в фиксированный период, используя следующую услугу.
Во-первых, у меня есть следующий класс для установки AlarmManager
.
public class FirebaseHandler {
private Context context;
private static final long FIREBASE_ALARM_CYCLE_TIME = 300000;
// constructors
public FirebaseHandler(Context context) {
this.context = context;
}
// set alarm
public void setAlarm() {
// create pending intent
Intent intent = new Intent(context, AlarmReceiver.class);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
AlarmReceiver.ALARM_REQUEST_CODE,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// create alarm
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarm.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + FIREBASE_ALARM_CYCLE_TIME,
FIREBASE_ALARM_CYCLE_TIME,
pendingIntent);
}
}
Я просто инициирую это, вызывая new FirebaseHandler(getApplicationContext()).setAlarm()
где-то в действии. Класс AlarmReceiver
выглядит следующим образом.
public class AlarmReceiver extends WakefulBroadcastReceiver {
public static final int ALARM_REQUEST_CODE = 12345;
@Override
public void onReceive(Context context, Intent wakefulIntent) {
Intent intent = new Intent(context, FirebaseAlarmService.class);
startWakefulService(context, intent);
}
}
Класс FirebaseAlarmService
выглядит следующим образом.
public class FirebaseAlarmService extends Service {
private static final String CLASSNAME = FirebaseAlarmService.class.getSimpleName();
private HandlerThread handlerThread;
// onStartCommand
@Override
public int onStartCommand(final Intent intent, int flags, final int startId) {
// start a new thread
// this depends on your need. I need to do a continuous operation for some time
// you can use IntentService too
handlerThread = new HandlerThread(CLASSNAME);
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
Runnable runnable = new Runnable() {
@Override
public void run() {
// all your codes here for the background task...
// remember to release the wake lock and stop service
AlarmReceiver.completeWakefulIntent(wakefulIntent);
stopSelf();
}
return START_NOT_STICKY;
}
// this is the part that does the trick
@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
// when the service is killed, start it again
new FirebaseHandler(getApplicationContext()).setAlarm();
}
// onDestroy
@Override
public void onDestroy() {
super.onDestroy();
// make sure to quit the thread
handlerThread.quit();
}
}
Таким образом, FirebaseHandler
устанавливает AlarmManager
, который будет периодически вызывать WakefulBroadcastReceiver
, который будет периодически запускать Service
. Когда служба будет убита, сама служба снова запустит AlarmManager
onTaskRemoved
.
В AndroidManifest
вам нужно будет добавить следующие разрешения для блокировки бодрствования.
<uses-permission android:name="android.permission.WAKE_LOCK" />
Также не забудьте добавить ресивер.
<receiver
android:name=".receiver.AlarmReceiver"
android:process=":remote" />
БОНУС: вы можете запустить службу после перезагрузки телефона или обновления приложения через PlayStore. Создайте еще один WakefulBroadcastReceiver
.
public class BootBroadcastReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(Context context, Intent wakefulIntent) {
// check if user is login, then set the alarm
if (isLogin) {
new FirebaseHandler(context).setAlarm();
}
// remove wake lock
WakefulBroadcastReceiver.completeWakefulIntent(wakefulIntent);
}
}
В AndroidManifest
добавьте требуемое разрешение.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Добавьте фильтр намерений.
<receiver android:name=".receiver.BootBroadcastReceiver">
<intent-filter>
<!-- get notified on reboot -->
<action android:name="android.intent.action.BOOT_COMPLETED" />
<!-- get notified on app updated -->
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
СОВЕТЫ. Иногда вы обнаружите, что вышеуказанный метод не будет работать. В основном это не ваша вина. Это вызвало это настройки безопасности телефона, особенно телефоны Mi. Пользователю необходимо "доверять" приложение и включить "автозапуск" в настройках телефона, тогда все должно работать нормально.
Ответ 6
Отображение уведомлений - это общая функциональность служб Android, и уже есть много вопросов о том, как запретить остановку служб или закрыть их.
Соответствующие вопросы перечислены ниже:
Android: как автоматически перезапустить приложение после того, как оно было закрыто",
Как предотвратить повреждение службы андроида (служба с уведомлением)
Как перезапустить службу в android?
Сохранить службу
Перезапустите службу, даже если приложение отключено и продолжает работать в фоновом режиме даже после закрытия приложения. Как?
Чтобы суммировать их, первым шагом является реализация BroadcastReceiver
, который прослушивает BOOT_COMPLETED
. Это будет означать, что ваша услуга активируется, когда устройство Android включено. Для этого в манифесте вставьте следующий код:
<receiver android:name=".MyBootCompletedReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
Убедитесь, что вы также включили законченное разрешение на загрузку:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
Затем реализуем BroadcastReceiver:
public class MyBootCompletedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent myService = new Intent(context, MyLongRunningService.class);
context.startService(myService);
}
}
При запуске службы вы можете вернуться START_STICKY
, которая сообщит ОС Android о перезапуске службы, если она будет отключена ОС в условиях ограниченной ресурсы:
public class MyLongRunningService extends Service {
@Override
public void onCreate() {
super.onCreate();
//inject dependencies if necessary
}
public int onStartCommand(Intent intent, int flags, int startId) {
//setup, then
return START_STICKY;
}
}
В общем, сервисы, запущенные приложениями, будут остановлены ОС Android, когда устройство будет мало ресурсов. Возврат START_STICKY
указывает ОС перезапустить службу, если ее необходимо остановить. Следовательно, гарантируя, что Служба запускается, когда устройство включено, и, попросив ее перезапустить, если она остановлена в условиях низкого ресурса, вы сделали службу, которая работает постоянно.
Это самый простой шаблон для обеспечения того, чтобы ваша Служба (и, следовательно, приложение) работала все время, что было вашим требованием.
Наверху есть дополнительные меры, которые вы можете принять, которые изложены в других ответах здесь, но их следует рассматривать как дополнение к реализации Службы, которая начинается с BOOT_COMPLETED
и что запросы перезапускаются, если она остановлена в условиях низких ресурсов.