IllegalStateException: WorkManager уже инициализирован

Имея эти зависимости:

dependencies {
    implementation "androidx.work:work-runtime:2.0.1"
    androidTestImplementation "androidx.work:work-testing:2.0.1"
}

При повторном запуске этого кода:

Configuration config = new Configuration.Builder().build();
WorkManager.initialize(getApplicationContext(), config);

this.workManager = WorkManager.getInstance();

Я получаю это сообщение об ошибке:

java.lang.IllegalStateException: WorkManager is already initialized.
Did you try to initialize it manually without disabling WorkManagerInitializer?
See WorkManager#initialize(Context, Configuration) or the class level Javadoc for more information.

и это также вызывает ошибку сегментации на нативной стороне:

A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR),
fault addr 0x878 in tid 10892 (ova.workmanager),
pid 10892 (ova.workmanager)

Это будет документация для WorkManager#initialize(Context, Configuration).


Цель состоит в том, чтобы предотвратить сбой во время ручной инициализации (чтобы изменить уровень журнала). Как отключить WorkManagerInitializer? Если возможно, я не хочу использовать ключевое слово static.


person Martin Zeitler    schedule 26.04.2019    source источник
comment
В вашем вопросе не хватает многих деталей. Вы действительно хотите инициализировать воркер более одного раза? Как вообще работает первая инициализация, правильно ли вы следовали документации? Где вы инициализировали воркер, какой класс и где именно в жизненном цикле этого класса?   -  person ronginat    schedule 27.04.2019
comment
@ronginat по сравнению с другими вопросами, он довольно подробный. и ваши вопросы, вероятно, уже получили ответ на этот вопрос. конечно, я не хочу инициализировать его дважды, и нет рабочих, необходимых для сбоя.   -  person Martin Zeitler    schedule 27.04.2019
comment
Пока вы ответили на мой первый вопрос, поэтому я знаю, что вы не хотите делать что-то невозможное (вы не можете инициализировать воркер более одного раза). Если ваш код запускается несколько раз и пытается инициализировать воркер, то это, вероятно, не подходящее место для него. Вот почему я спросил, где вы инициализируете воркера и как в первый раз работает без каких-либо изменений в вашем манифесте (я предполагаю, что вы не изменили манифест, как написано в вашем ответе при написании этого вопроса).   -  person ronginat    schedule 27.04.2019
comment
@ronginat, если быть точным, это происходит при планировании одного задания, а затем при планировании другого; также при попытке отменить задание. сложность в том, что .getInstance() - это static метод, а не метод экземпляра. этот ответ - всего лишь подход, который я нашел, основываясь на предложении в сообщении об ошибке; все еще нужно проверить это (сообщение в блоге - только похожая ситуация).   -  person Martin Zeitler    schedule 27.04.2019
comment
Тогда самым безопасным способом будет инициализировать его только один раз в Application#onCreate, как это предлагается в официальное руководство (сразу под блоком кода). После этого свободно используйте статический getInstance в любом месте вашего кода, потому что WorkManager уже был инициализирован.   -  person ronginat    schedule 27.04.2019


Ответы (4)


Вот как заменить провайдера androidx.work.impl.WorkManagerInitializer:

<application>
    ...

    <!-- disable default provider -->
    <provider
        android:name="androidx.work.impl.WorkManagerInitializer"
        android:authorities="${applicationId}.workmanager-init"
        android:exported="false"
        android:enabled="false"/>

    <!-- register custom provider -->
    <provider
        android:name=".CustomWorkManagerInitializer"
        android:authorities="${applicationId}.WorkManagerInit"/>

</application>

Источник: Инициализация Custom Work Manager (на Kotlin).


Если не зарегистрировать другого поставщика, это дает:

java.lang.IllegalStateException: WorkManager is not initialized properly. The most
likely cause is that you disabled WorkManagerInitializer in your manifest but forgot
to call WorkManager#initialize in your Application#onCreate or a ContentProvider.

И ContentProvider зарегистрирован в src/debug/Manifest.xml:

public class WorkManagerInit extends ContentProvider {

    @Override
    public boolean onCreate() {
        if(getContext() != null) {
            Configuration config = new Configuration.Builder().build();
            WorkManager.initialize(getContext().getApplicationContext(), config);
        }
        return true;
    }
    ...
}
person Martin Zeitler    schedule 26.04.2019
comment
реальная проблема заключалась в том, что он был синглтоном - в то время как ContentProvider.onCreate() и Application.onCreate(), похоже, вызываются только один раз, поэтому запускать можно только там. В Activity это также может работать при проверке savedInstanceState != null. - person Martin Zeitler; 28.04.2019

WorkManager - это синглтон, его необходимо настроить перед использованием, и вы не можете изменить его конфигурацию без перезапуска приложения.

Второй вызов инициализации вызывает исключение, чтобы указать, что он не может использовать эту конфигурацию, если WorkManager уже был инициализирован. Это дизайнерское решение было принято во время первых альфа-выпусков, чтобы избежать сбоев в автоматическом режиме (workmanager-1.0.0-alpha11).

WorkManager v2.1 добавляет способ по запросу к инициализировать библиотеку, чтобы вы могли переместить фактическую инициализацию из последовательности горячего старта вашего приложения. Однако у вас все еще есть ограничения: WorkManager можно настроить только один раз.

С новой конфигурацией по требованию вы должны добавить Configuration.Provider интерфейс в свое приложение, как здесь:

class MyApplication : Application(), Configuration.Provider {

   override fun getWorkManagerConfiguration(): Configuration =
       // provide custom configuration
       Configuration.Builder()
               .setMinimumLoggingLevel(android.util.Log.INFO)
               .setWorkerFactory(MyWorkerFactory())
               .build()
}

Затем, когда вам нужно использовать WorkManager, вместо использования WorkManager#getInstance() (который теперь не рекомендуется) вы должны использовать новый:

WorkManager#getInstance(context)

В этом случае метод getInstance проверяет, инициализирован ли WorkManager уже или нет. Если он еще не инициализирован, он получает конфигурацию с помощью метода getWorkManagerConfiguration(), а затем инициализирует WorkManager. Таким образом, вы больше не звоните WorkManager#initialize(), полностью избегая проблемы.

В официальную документацию добавлена эти дополнительные детали.

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

person pfmaggi    schedule 28.04.2019
comment
обновление конфигурации позже не требуется, но можно использовать метод, который сообщает состояние инициализации ... иначе не может инициализировать OnDemand, а только OnCreate. и без этого метода сборки отладки / выпуска могут быть единственным способом переключения поставщиков. - person Martin Zeitler; 28.04.2019
comment
Сообщите мне, покрывают ли дополнительные сведения о новом синтаксисе по запросу ваш вопрос. В этом случае вы никогда не вызываете инициализацию, а getInstance (context) позаботится об инициализации WorkManager, если это необходимо. - person pfmaggi; 28.04.2019

Вы можете контролировать, когда вы вызываете workManager

if(this.workManager == null){
   Configuration config = new Configuration.Builder().build();
   WorkManager.initialize(getApplicationContext(), config);
   this.workManager = WorkManager.getInstance();
}
person Beyazid    schedule 26.04.2019
comment
это будет вызывать initialize во второй раз (или чаще) - person user85421; 27.04.2019
comment
this.workManager == null всегда будет оцениваться как true. - person Martin Zeitler; 27.04.2019

Если вы хотите инициализировать WorkerManager, вы должны поместить его в onCreate вашего пользовательского класса Application, чтобы он был вызван только один раз. После этого вы можете получить экземпляр только тогда, когда он вам нужен, не беспокоясь. Не рекомендуется инициализировать Worker Manager. Зачем тебе это надо?

person Gerardo Suarez    schedule 26.04.2019