WorkManager crashes trying to enqueue unique periodic work in Application#onCreate [closed]
Asked Answered
C

1

6

I want to use WorkManager together with Dagger 2 to inject dependencies into workers. I followed this article to implement the setup. The part of the setup is on-demand initialization. To achieve it I added the following lines into my manifest file:

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

and made my application class implement the Configuration.Provider interface like this:

    @NonNull
    @Override
    public Configuration getWorkManagerConfiguration() {
        return new Configuration.Builder().setMinimumLoggingLevel(Log.DEBUG).setWorkerFactory(delegatingWorkerFactory).build();
    }

Dagger setup works as expected.

However I encountered the following problem: in Application#onCreate I enqueue unique periodic task and on the very first installation of the application this action always fails with the following error:

java.lang.IllegalStateException: The file system on the device is in a bad state. WorkManager cannot access the app's internal data store.
    at androidx.work.impl.utils.ForceStopRunnable.run(ForceStopRunnable.java:115)
    at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:91)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:764)
 Caused by: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14 SQLITE_CANTOPEN): Could not open database
    at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
    at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:211)
    at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:195)
    at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:503)
    at android.database.sqlite.SQLiteConnectionPool.tryAcquireNonPrimaryConnectionLocked(SQLiteConnectionPool.java:987)
    at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:693)
    at android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:378)
    at android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
    at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:586)
    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
    at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
    at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:46)
    at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1408)
    at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1383)
    at androidx.sqlite.db.framework.FrameworkSQLiteDatabase.query(FrameworkSQLiteDatabase.java:161)
    at androidx.room.RoomDatabase.query(RoomDatabase.java:328)
    at androidx.room.util.DBUtil.query(DBUtil.java:83)
    at androidx.work.impl.model.PreferenceDao_Impl.getLongValue(PreferenceDao_Impl.java:70)
    at androidx.work.impl.utils.PreferenceUtils.getNeedsReschedule(PreferenceUtils.java:96)
    at androidx.work.impl.utils.ForceStopRunnable.shouldRescheduleWorkers(ForceStopRunnable.java:187)
    at androidx.work.impl.utils.ForceStopRunnable.run(ForceStopRunnable.java:88)
    at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:91) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
    at java.lang.Thread.run(Thread.java:764) 

If I move the code that enqueue my work out from the Application#onCreate into later stage of the application lifecycle (some activity for example) then it doesn't fail.

I haven't found any restrictions on enqueuing work from Application#onCreate so I expect it must work. I'm using WorkManager 2.3.4 and Room 2.2.5. I tried to downgrade Room to 2.2.2 and WorkManager down to several older stable versions as well, but it didn't help. Issue is reproducible on different devices and emulators with different Android versions.

How can I address this issue and keep enqueuing work in Application#onCreate?

EDIT Here's how I enquee the work:

workManagerProvider.get().enqueueUniquePeriodicWork(
        "Unique name",
        ExistingPeriodicWorkPolicy.REPLACE,
        request
    )

where workManagerProvider is Provider<WorkManager>. I can't access the workmanager directly due to circular dependency, so I had to get a provider from dagger and only then use it. It is not related to the topic.

Certification answered 20/5, 2020 at 10:7 Comment(4)
From the error it is understood it is because the database cannot be opened. I think the database is not initialized before you enqueue the work in Application#onCreateDistort
@Distort that's true, but it is the database, which is managed by WorkManager. So I have no idea what prevents WorkManager from initializing it exclusively on the very first run.Certification
Can you add the code that shows how you enqueue your work?Sholokhov
Dagger2 and WorkManager is being used here in your code, And both has their own way for initialisation STEP's, So better to share complete sample code how you are trying to implement it else try to "enqueueUniquePeriodicWork " without using Dagger2 here and see if this is working for you.Venomous
C
1

The issue was caused by another piece of code, which was wiping application's internal data on the first launch. Wipe was performed kinda in parallel with the WorkManager's internal database creation. Because of that, during initialization WorkManager tried to access the SQLite connection for the already deleted database file and that led to the crash.

Certification answered 14/6, 2020 at 15:17 Comment(2)
ok but, how did you fixed this?Methodism
@LuizAlegria I made that code not touch the WorkManager's DB.Certification

© 2022 - 2024 — McMap. All rights reserved.