IllegalStateException: WorkManager is already initialized
Asked Answered
D

6

31

Having these dependencies:

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

When running this code for the second time:

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

this.workManager = WorkManager.getInstance();

I get this error message:

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.

and it also throws a segmentation fault on the native side:

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

This would be the documentation for WorkManager#initialize(Context, Configuration).


The intent is to prevent the crash during manual initialization (in order to change the log level). How to disable the WorkManagerInitializer? If possible, I do not want to use the static keyword.

Disremember answered 26/4, 2019 at 21:36 Comment(5)
Your question is missing a lot of details. Do you actually want to initialize the worker more than once? How does the first initialization even work, did you follow the documentation for initializing it properly? Where did you initialize the worker, which class and exactly where in this class's lifecycle?Hankypanky
@Hankypanky compared to other questions, it is quite detailed. and you questions are probably all answered by the question already. of course I do not want to initialize it twice and there are no workers required to produce the crash.Disremember
So far you answered to my first question so i know you don't want to do something impossible (you can't initialize the worker more than once). If your code is running multiple times and trying to initialize the worker, then it's probably not the right place for it. That's why i asked where you initialize the worker and how the first time is working without any change in your manifest (i'm guessing you didn't change the manifest as written in your answer when writing this question).Hankypanky
@Hankypanky to be precise, it happens when scheduling one job and then later scheduling another; also when trying to cancel jobs. the tricky thing about it is, that .getInstance() is a static method and not an instance method. that answer is just an approach I've found, based upon the suggestion in the error message; still need to test that (the blog post is only a similar situation).Disremember
Then the safest way will be initializing it only once at Application#onCreate as suggested in the official guide (just below the code block). After that, use the static getInstance freely anywhere in your code because the WorkManager had already been initialized.Hankypanky
D
18

This is how to substitute provider 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>

Source: Custom Work Manager initialization (in Kotlin).


Unless registering another provider, this gives a:

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.

And the ContentProvider registered in the 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;
    }
    ...
}
Disremember answered 26/4, 2019 at 22:21 Comment(1)
it being a singleton was the actual problem - while ContentProvider.onCreate() and Application.onCreate() seem to be invoked once only, so one can only run the in there. In an Activity is might also work, when checking for savedInstanceState != null.Disremember
M
21

Since WorkManager 2.6, App Startup is used internally within WorkManager. To provide a custom initializer you need to remove the androidx.startup node.

If you don't use App Startup in your app, you can remove it completely.

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    tools:node="remove">
</provider>

Otherwise, remove only the WorkManagerInitializer node.

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">

    <!-- If you are using androidx.startup to initialize other components -->
    <meta-data
        android:name="androidx.work.WorkManagerInitializer"
        android:value="androidx.startup"
        tools:node="remove" />
</provider>

While using a version of WorkManager older than 2.6, remove workmanager-init instead:

<provider
    android:name="androidx.work.impl.WorkManagerInitializer"
    android:authorities="${applicationId}.workmanager-init"
    tools:node="remove" />
Marvismarwin answered 2/9, 2021 at 10:11 Comment(0)
D
18

This is how to substitute provider 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>

Source: Custom Work Manager initialization (in Kotlin).


Unless registering another provider, this gives a:

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.

And the ContentProvider registered in the 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;
    }
    ...
}
Disremember answered 26/4, 2019 at 22:21 Comment(1)
it being a singleton was the actual problem - while ContentProvider.onCreate() and Application.onCreate() seem to be invoked once only, so one can only run the in there. In an Activity is might also work, when checking for savedInstanceState != null.Disremember
S
9

WorkManager is a singleton, it needs to be configured before being used and you cannot change it's configuration without restarting the application.

A second call to initialize throws an exception to indicate that it cannot use that configuration if WorkManager has already been initialized. This was a design decision taken during the initial alpha releases to avoid to fail silently (workmanager-1.0.0-alpha11).

WorkManager v2.1 adds an on-demand way to initialize the library, so you can move the actual initialization out from the hot-start sequence of your app. However you still have the constraints that WorkManager can only be configured once.

With the new on-demand configuration, you've to add a Configuration.Provider interface to your application like here:

class MyApplication : Application(), Configuration.Provider {

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

Then, when you need to use WorkManager, instead of using WorkManager#getInstance() (that is now deprecated), you should use the new:

WorkManager#getInstance(context)

In this case, the getInstance method, check if WorkManager it's already initialized or not. If it's not yet initialized, it retrieves the configuration using the getWorkManagerConfiguration() method and then it initializes WorkManager. In this way, you don't call anymore WorkManager#initialize() completely avoiding the problem.

The official documentation has been updated with these additional details.

If you think that WorkManager should allows to update it's configuration after it has been initialized, you should add a feature request to the library's issue tracker.

Supralapsarian answered 28/4, 2019 at 8:40 Comment(2)
updating the configuration later on is not required, but it could use a method which tells the state of initialization... else once cannot initialize OnDemand, but only OnCreate. and without that method, debug/release builds might be the only way to switch providers.Disremember
Let me know if the additional details on the new on-demand syntax do cover your question. In this case, you never call initialize and getInstance(context) takes care of initializing WorkManager if necessarySupralapsarian
P
4

for solving this problem disable default provider from manifest

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

and replace the following code

 <provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.workmanager-init"
        tools:node="remove" />
Prismoid answered 13/10, 2021 at 20:6 Comment(0)
F
1

You can control when you called workManager

if(this.workManager == null){
   Configuration config = new Configuration.Builder().build();
   WorkManager.initialize(getApplicationContext(), config);
   this.workManager = WorkManager.getInstance();
}
Facial answered 26/4, 2019 at 21:56 Comment(2)
this will still call initialize a second time (or more often)Hieratic
this.workManager == null will always evaluate to true.Disremember
B
0

If you want to initialize the WorkerManager you must put this in the onCreate of your custom Application class, so this only be called once. After that you can only get the instance when you need it without worries. It is not recommended to initialize the Worker Manager. Why do you need that?

Bianchi answered 26/4, 2019 at 23:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.