Проблема: мне нужно запускать код при каждом запуске, прежде чем мое приложение будет готово к использованию.
Сначала я пробовал делать это в отдельном занятии.
AndroidManifest.xml
<activity android:name = ".MainActivity" />
<activity android:name = ".StarterActivity">
<intent-filter>
<action android:name = "android.intent.action.MAIN" />
<category android:name = "android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
AppLoader.java
public class AppLoader {
private static Object someInstance;
public static void load(Runnable onCompleteCallback) {
try {
someInstance = new Object();
//potentially long operation to initialize the app
Thread.sleep(5000);
onCompleteCallback.run();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void checkInitialized() {
if (someInstance == null) {
throw new RuntimeException("Not initialized");
}
}
}
StarterActivity.java
public class StarterActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppLoader.load(() -> {
MainActivity.start(this);
finish();
});
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static void start(Context context) {
Intent starter = new Intent(context, MainActivity.class);
context.startActivity(starter);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppLoader.checkInitialized();
}
}
Это отлично работает, если приложение запускается холодным способом с помощью значка запуска, но дает сбой во всех остальных случаях. Простой способ воспроизвести проблему:
Вот статья, описывающая похожую проблему: Смерть процесса Android - и (большие) последствия для вашего приложения
Возможные решения:
Итак, как правильно запускать код каждый раз при запуске приложения?
Примечание. Обычно StarterActivity представляет собой заставку, вводится AppLoader и т. д., Но я оставил это для простоты.
AndroidManifest.xml
<application
android:name = ".AppLoader"
AppLoader.java
public class AppLoader extends Application {
private static Object someInstance;
@Override
public void onCreate() {
super.onCreate();
// DO YOUR STUFF
}
}
Обновлять
- Используйте Handler с заставкой.
public class StarterActivity extends AppCompatActivity {
private Handler handler;
private Runnable myStuffRunnable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new Handler();
myStuffRunnable = new Runnable(){
public void run(){
// DO MY STUFF
MainActivity.start(this);
}
};
}
@Override
protected void onPause() {
handler.removeCallbacks(myStuffRunnable);
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
handler.post(myStuffRunnable);
}
@Override
protected void onDestroy() {
handler.removeCallbacks(myStuffRunnable);
super.onDestroy();
}
}
Если вы ожидаете, что ваш материал займет много времени, используйте IntentService и зарегистрируйтесь на baseActivity. Но если всего 5-10 секунд, то используйте Handler на заставке.
Проверьте мое обновление ответа с помощью Handler, и это позволит вам сделать некоторую анимацию прогресса для хорошего взаимодействия с пользователем, пока вы не сделаете свою работу.
Возможно, я неправильно сформулировал свой вопрос, но речь не шла о потоковой передаче / обновлении пользовательского интерфейса и т. д., Я пытался найти лучший способ выполнить некоторый код при каждом запуске (но не в onCreate of App). Решение Handler все равно выйдет из строя, если пользователь напрямую откроет MainActivity. По этой причине я просто перенаправлялся на StarterActivity, если это было необходимо. Спасибо за вашу помощь!
Ваше приложение генерирует исключение RuntimeException, которое вы установили в методе AppLoader.checkInitialized (), потому что ваш объект someInstance теряет свое состояние, когда приложение переходит в фоновый режим и его убивает система (потому что вы настроили свое устройство на нулевые фоновые потоки) . Итак, когда вы пытаетесь повторно открыть приложение, система запускает MainActivity напрямую (а не StarterActivity), потому что пытается восстановить его предыдущее состояние. Но переменные не восстанавливаются, даже статические переменные.
Итак, если вам нужен Object someInstance в вашей MainActivity, вы должны интегрировать его создание в жизненный цикл MainActivitie, переопределив такие методы, как onSavedInstanceState, onRestoreInstanceState и т. д., Чтобы правильно обрабатывать и повторно загружать этот объект, если ваше приложение будет убито системой.
Взгляните на этот https://developer.android.com/guide/components/activities/activity-lifecycle
Если кому-то интересно, я просто перенаправлял пользователя на StarterActivity, если это необходимо, чтобы убедиться, что необходимый код выполняется при каждом запуске.
public abstract class BaseActivity extends AppCompatActivity {
private boolean isCreated;
@Override
protected final void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!appLoader.isLoaded()) {
StarterActivity.start(this);
finish();
return;
}
onCreateActivity(savedInstanceState);
isCreated = true;
}
protected void onCreateActivity(@Nullable Bundle savedInstanceState) {
}
@Override
protected final void onDestroy() {
super.onDestroy();
if (isCreated) {
onDestroyActivity();
}
}
protected void onDestroyActivity() {
}
}
Все активности расширяют BaseActivity (кроме StarterActivity) и перекрывают onCreateActivity / onDestroyActivity вместо onCreate / onDestroy.
Но что, если "делать свое дело" займет 5-10 секунд? Я подозреваю, что это, по крайней мере, вызовет «чрезмерное время запуска» в Android Vitals и, возможно, ANR тоже. Или нет? Я предполагаю, что я пытаюсь сделать это 1) Сделать так, чтобы приложение было отзывчивым при его загрузке (экран-заставка) 2) Но не знаю, как обрабатывать случаи, когда процесс завершается в фоновом режиме.