Reputation: 42642
I'm getting the following new error, when I upgrade WorkManager from "2.2.0" to "2.3.0-rc01"
The error occurs when I'm exporting APK.
C:\app: Error: Remove androidx.work.impl.WorkManagerInitializer from your AndroidManifest.xml when using on-demand initialization. [RemoveWorkManagerInitializer]
Explanation for issues of type "RemoveWorkManagerInitializer":
If an android.app.Application implements
androidx.work.Configuration.Provider,
the default androidx.work.impl.WorkManagerInitializer needs to be removed
from the
AndroidManifest.xml file.
I'm not sure why I didn't get such error in 2.2.0, as "On-Demand Initialization" is introduced since 2.1.0.
According to https://developer.android.com/topic/libraries/architecture/workmanager/advanced/custom-configuration#remove-default
I'm not kinna sure, whether it is a right thing to include the following in my AndroidManifest.xml
.
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
tools:node="remove" />
Currently, the following is my Application
class.
public class MyApplication extends MultiDexApplication implements Configuration.Provider {
private static MyApplication me;
@Override
public void onCreate() {
super.onCreate();
me = this;
}
public static MyApplication instance() {
return me;
}
@NonNull
@Override
public Configuration getWorkManagerConfiguration() {
return new Configuration.Builder()
.build();
}
}
public static WorkManager getWorkManager() {
MyApplication myApplication = MyApplication.instance();
if (myApplication == null) {
// Very rare edge case. Not sure how it happens. But, it happens :)
return WorkManager.getInstance();
} else {
return WorkManager.getInstance(myApplication);
}
}
It seems that there is rare chance that "Default initialization" (WorkManager.getInstance()
) is being executed too, when the Application
class is null.
I can easily eliminate error during APK exporting, by including the following provider
. But, is that a right thing to to so?
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
tools:node="remove" />
Upvotes: 34
Views: 15750
Reputation: 431
If you are getting this error after updating to WorkManager
2.6.0 or higher, you have to use this snippet in your manifest:
<application>
...
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
</application>
Upvotes: 25
Reputation: 12347
Yes you need to remove the default work manager initializer as you did if you want to use on-demand initialization, so keep the following piece of code in your manifest:
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
tools:node="remove" />
Also the above documentation clearly state that you should not be calling WorkManager.getInstance()
(without the Context
argument):
Note: If you call the deprecated no-parameter WorkManager.getInstance() method before WorkManager has been initialized, the method throws an exception. You should always use the WorkManager.getInstance(Context) method, even if you're not customizing WorkManager.
After looking at the androix/work changelog you will see that a new feature was added in version 2.3.0-beta02:
The reason why you have this error after upgrading from version 2.2.0 to 2.3.0.rc1 is because, the android team added a RemoveWorkManagerInitializerDetector that would throw the exception you got in the following pull request at build time.
Now about the source code, I suggest you tight the getWorkManager
method to the application directly like below:
import androidx.annotation.NonNull;
import androidx.work.Configuration;
import androidx.work.WorkManager;
public class App extends MultiDexApplication implements Configuration.Provider {
private static App APP_INSTANCE;
@Override
public void onCreate() {
super.onCreate();
APP_INSTANCE = this;
}
public static App getInstance() {
return APP_INSTANCE;
}
@NonNull
@Override
public Configuration getWorkManagerConfiguration() {
return new Configuration.Builder()
.build();
}
public static WorkManager getWorkManager() {
return WorkManager.getInstance(APP_INSTANCE);
}
}
And just call App.getWorkManager()
whenever you need to in the app source code
You could do something equivalent for your ContentProvider if there is any.
PS: Interesting codelabs tutorials exits for java or kotlin
Upvotes: 7
Reputation: 21104
We introduced this lint rule in WorkManager 2.3.0-*
. The problem we are trying to address with this Lint rule is that if you have both the WorkManagerInitializer
ContentProvider
and your Application
subtype implements Configuration.Provider
(for on-demand initialization) - the ContentProvider
will always take precedence.
This might be unexpected, especially when you have additional Configuration
which will not take effect because the ContentProvider
always uses the default configuration.
All you really need to do is to remove the default provider. That way initialization will no longer be eager, but be on-demand.
Upvotes: 13
Reputation: 7283
WorkManagerInitializer
is used to provide a context to WorkManager
. This happens because content providers are initialized before the Application
(See this question). This is the reason you need to provide the context yourself if you do custom initialization. So if you use the custom initialization, you shouldn't need it.
If you're calling the getWorkManager
method from a content provider then your application instance will be null
. To resolve this issue just pass the context as a parameter to the method by calling getContext
inside the content provider:
public static WorkManager getWorkManager(Context context) {
return WorkManager.getInstance(context);
}
public class MyContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
WorkManager workManager = getWorkManager(getContext());
...
}
...
}
Upvotes: 1