android: процесс вызывает повторный вызов метода onCreate моего приложения. Как я могу предотвратить повторное выполнение кода?

#android

#Android

Вопрос:

Я знаю, что если я использую android:process в манифесте, то класс, который расширяет Application, будет вызываться дважды. Один раз для приложения и второй раз для нового процесса.

Проблема в том, что у меня есть код в MyApplication (расширяет приложение), который не следует вызывать дважды. Я хочу иметь отдельный процесс, но я хочу, чтобы код в MyApplication#onCreate запускался только один раз за загрузку.

Я попытался установить флаг в общих настройках, но он не работает, вероятно, из-за проблемы с различными процессами

Есть идеи?

Комментарии:

1. Общие настройки кажутся нормальными. Почему это не сработало?

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

Ответ №1:

Основная причина

Из документации SharedPreferences:

Примечание: этот класс не поддерживает использование в нескольких процессах.

Это объясняет, почему ваш SharePreferences не работает.

Решение 1: использование Context.MODE_MULTI_PROCESS, но оно устарело на уровне API 23

public static final int MODE_MULTI_PROCESS

Эта константа устарела на уровне API 23.

MODE_MULTI_PROCESS работает ненадежно в некоторых версиях Android и, кроме того, не предоставляет никакого механизма для согласования одновременных изменений между процессами. Приложения не должны пытаться его использовать. Вместо этого они должны использовать явный межпроцессный подход к управлению данными, такой как ContentProvider.

Решение 2: использование ContentProvider

2.1. Напишите свой собственный ContentProvider

  • Нам просто нужен способ сохранить логическую переменную, которая указывает onCreate() MyApplication , вызывается метод в первый раз или нет, использование этого решения кажется неэффективным.

2.2. Используйте предопределенные ContentProvider из Android

  • Приложение должно объявлять разрешения на чтение / запись во внешнее хранилище, а также запрашивать разрешения времени выполнения. Кстати, это сбивает пользователей с толку при первом открытии приложения.

Решение 3: мы можем использовать приведенный ниже поток для реализации

  • Объявите a BroadcastReceiver , который выполняется в том же процессе, что и ваше приложение. Потому что они выполняются в одном и том же процессе, поэтому у них одинаковый идентификатор процесса.
  • Компонент (activity, service, receiver, provider), который выполняется в отдельном процессе (частном или глобальном), поэтому у них будет другой идентификатор процесса.

Реализация

Шаг 1. Создайте класс, который расширяется от BoardcastReceiver , named AppReceiver .

 public class AppReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Messenger messenger = intent.getParcelableExtra(MyApplication.EXTRA_MESSENGER);

        int processId = intent.getIntExtra(MyApplication.EXTRA_PROCESS_ID, -1);
        boolean isOnCreateCalledFirstTime = processId == Process.myPid();

        Message message = Message.obtain();
        message.arg1 = isOnCreateCalledFirstTime ? 1 : 0;
        try {
            messenger.send(message);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}
 

Шаг 2. Добавьте этот класс в AndroidManifest.xml

 <receiver
    android:name=".AppReceiver"
    android:enabled="true"
    android:exported="true" />
 

Шаг 3. Измените свой MyApplication класс

 public class MyApplication extends Application {

    public static final String EXTRA_MESSENGER = "EXTRA_MESSENGER";
    public static final String EXTRA_PROCESS_ID = "EXTRA_PROCESS_ID";

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

        Intent intent = new Intent();
        String pkg = getPackageName();
        intent.setComponent(new ComponentName(pkg, pkg   ".AppReceiver"));

        Handler handler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
            @Override
            public boolean handleMessage(@NonNull Message msg) {
                boolean isOnCreateCalledFirstTime = msg.arg1 != 0;
                if (isOnCreateCalledFirstTime) {
                    // TODO: First time onCreate() is called
                } else {
                    // TODO: Next time onCreate() is called
                }
                return true;
            }
        });
        Messenger messenger = new Messenger(handler);

        intent.putExtra(EXTRA_MESSENGER, messenger);
        intent.putExtra(EXTRA_PROCESS_ID, Process.myPid());

        sendBroadcast(intent);
    }
}