Во-первых, я знаю, что на самом деле не следует убивать / перезапускать приложение на Android. В моем случае использования я хочу восстановить заводские настройки своего приложения в конкретном случае, когда сервер отправляет конкретная информация для клиента.
Пользователь может войти в систему на сервере только с ОДНИМ экземпляром приложения (т. е. использование нескольких устройств не допускается). Если другой экземпляр получает эту блокировку для входа в систему, тогда все остальные экземпляры этого пользователя должны удалить свои данные (восстановить заводские настройки), чтобы сохранить согласованность.
Можно принудительно получить блокировку, потому что пользователь может удалить приложение и переустановить его, что приведет к другому идентификатору экземпляра, и пользователь больше не сможет освободить блокировку. Следовательно, можно принудительно получить блокировку.
Из-за этой возможности принудительного использования нам нужно всегда проверять в конкретном случае, что он имеет блокировку. Это делается (почти) при каждом запросе к серверу. Сервер может отправить «неправильный идентификатор блокировки». Если это обнаружено, клиентское приложение должно удалить все.
Это был пример использования.
У меня есть Activity
A, которое запускает действие Login Activity
L или основное Activity
B приложения в зависимости от значение sharedPrefs. После запуска L или B он закрывается, так что работают только L или B. Таким образом, в случае, если пользователь уже вошел в систему, B сейчас работает.
B запускает C. C вызывает startService
для IntentService
D. В результате получается следующий стек:
(A)> B> C> D
Из метода onHandleIntent объекта D событие отправляется в ResultReceiver R.
R теперь обрабатывает это событие, предоставляя пользователю диалоговое окно, в котором он может сбросить настройки приложения до заводских (удалить базу данных, sharedPrefs и т. д.)
После сброса настроек я хочу перезапустить приложение (чтобы закрыть все действия) и снова запустить только A, который затем запускает логин Действие
L и завершается само:
(A)> L
Метод onClick диалогового окна выглядит так:
@Override
public void onClick(DialogInterface dialog, int which) {
// Will call onCancelListener
MyApplication.factoryReset(); // (Deletes the database, clears sharedPrefs, etc.)
Intent i = new Intent(MyApp.getContext(), A.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MyApp.getContext().startActivity(i);
}
И это класс MyApp
:
public class MyApp extends Application {
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
public static Context getContext() {
return context;
}
public static void factoryReset() {
// ...
}
}
проблема в том, что если я использую FLAG_ACTIVITY_NEW_TASK
, действия B и C все еще выполняются. Если я нажму кнопку «Назад» при входе в систему Activity
, я вижу C, но хочу вернуться на главный экран.
Если я не установил FLAG_ACTIVITY_NEW_TASK
, я получаю ошибка:
07-07 12:27:12.272: ERROR/AndroidRuntime(9512): android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
Я не могу использовать Контекст действий
, потому что ServiceIntent
D также может быть вызван из фоновой задачи, которая запускается AlarmManager
.
Итак, как я могу решить эту проблему, чтобы стек действий стал (A)> L?
Я нашел, что это работает над API 29 и позже - в целях уничтожения и перезапуска приложения, как будто пользователь запустил его, когда это не работало.
public void restartApplication(final @NonNull Activity activity) {
// Systems at 29/Q and later don't allow relaunch, but System.exit(0) on
// all supported systems will relaunch ... but by killing the process, then
// restarting the process with the back stack intact. We must make sure that
// the launch activity is the only thing in the back stack before exiting.
final PackageManager pm = activity.getPackageManager();
final Intent intent = pm.getLaunchIntentForPackage(activity.getPackageName());
activity.finishAffinity(); // Finishes all activities.
activity.startActivity(intent); // Start the launch activity
System.exit(0); // System finishes and automatically relaunches us.
}
, Который был сделан, когда действие средства запуска в приложении имеет это:
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
я видел, что комментарии утверждают, что категория ЗНАЧЕНИЯ ПО УМОЛЧАНИЮ необходима, но я не нашел, что это имеет место. Я подтвердил, что Объект приложения в моем приложении воссоздается, таким образом, я полагаю, что процесс действительно был уничтожен и перезапущен.
единственная цель, для которой я использую это, состоит в том, чтобы перезапустить приложение после того, как пользователь включил или отключил катастрофический отказ, сообщающий для Firebase Crashlytics. Согласно их документам, приложение должно быть перезапущено (процесс, уничтоженный и воссозданный) для того изменения для вступления в силу.