Предварительно заполнить базу данных комнат с помощью WorkManager и Dagger - PullRequest
1 голос
/ 16 марта 2019

Я пытаюсь использовать WorkManager для заполнения базы данных комнат при создании базы данных. Я использую кинжал для инициализации базы данных и ее Дао. При заполнении базы данных выдается следующая ошибка.

Could not instantiate *.*.*.SeedDatabaseWorker
    java.lang.NoSuchMethodException: <init> [class android.content.Context, class androidx.work.WorkerParameters]
        at java.lang.Class.getConstructor0(Class.java:2204)
        at java.lang.Class.getDeclaredConstructor(Class.java:2050)
        at androidx.work.WorkerFactory.createWorkerWithDefaultFallback(WorkerFactory.java:91)
        at androidx.work.impl.WorkerWrapper.runWorker(WorkerWrapper.java:233)
        at androidx.work.impl.WorkerWrapper.run(WorkerWrapper.java:127)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
        at java.lang.Thread.run(Thread.java:761)
2019-03-16 16:22:29.135 18035-18051/*.* E/WM-WorkerWrapper: Could not create Worker *.*.*.SeedDatabaseWorker

Вот как я настроил приложение.

AppModule.Kt

@Provides
@Singleton
fun provideAppDatabase(context: Context): AppDatabase {
    return Room.databaseBuilder(
        context,
        AppDatabase::class.java,
        "garden.db"
    )
        .addCallback(object : RoomDatabase.Callback() {
            override fun onCreate(db: SupportSQLiteDatabase) {
                super.onCreate(db)
                val request = OneTimeWorkRequestBuilder<SeedDatabaseWorker>().build()
                WorkManager.getInstance().enqueue(request)
            }
        })
        .build()
}

@Provides
@Singleton
fun providePlantDao(db: AppDatabase): PlantDao =
    db.plantDao()

PlantDao

@Dao
interface PlantDao {
    @Query("SELECT * FROM plants ORDER BY name")
    fun getPlants(): LiveData<List<Plant>>
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertAll(plants: List<Plant>)
}

AppDatabase.kt

@Database(
        entities = [
            Plant::class
        ],
        version = 1,
        exportSchema = false
)
abstract class AppDatabase : RoomDatabase() {

    abstract fun plantDao(): PlantDao
}

SeedDatabaseWorker.kt

class SeedDatabaseWorker @Inject constructor(
        context: Context,
        workerParameters: WorkerParameters
): CoroutineWorker(context, workerParameters) {


    private val TAG by lazy { SeedDatabaseWorker::class.java.simpleName }
    @Inject
    lateinit var database: AppDatabase
    override val coroutineContext = Dispatchers.IO

    override suspend fun doWork(): Result = coroutineScope {

        try {
            applicationContext.assets.open("plants.json").use { inputStream ->
                JsonReader(inputStream.reader()).use { jsonReader ->
                    val plantType = object : TypeToken<List<Plant>>() {}.type
                    val plantList: List<Plant> = Gson().fromJson(jsonReader, plantType)

                    database.plantDao().insertAll(plantList)

                    Result.success()
                }
            }
        } catch (ex: Exception) {
            Log.e(TAG, "Error seeding database", ex)
            Result.failure()
        }
    }
}

Может кто-нибудь помочь мне заполнить базу данных с помощью WorkManager? Примечание: я пытаюсь это Google образец

1 Ответ

0 голосов
/ 20 марта 2019

Пока что Dagger 2 официально не поддерживает инъекцию с androidx.worker.Worker, эта проблема все еще открыта, отметьте здесь . Это блог предлагает одно решение. По сути, вы можете вставить любой объект в конструктор, например:

class HelloWorldWorker @AssistedInject constructor(
    @Assisted private val appContext: Context,
    @Assisted private val params: WorkerParameters,
    private val foo: Foo
) : Worker(appContext, params) {
    private val TAG = "HelloWorldWorker"
    override fun doWork(): Result {
        Log.d(TAG, "Hello world!")
        Log.d(TAG, "Injected foo: $foo")
        return Result.success()
    }

    @AssistedInject.Factory
    interface Factory : ChildWorkerFactory
}

Здесь вводится объект Foo.

У меня та же проблема в моем проекте, вдохновленная блогом 1013 *, я решаю проблему. Вы можете проверить мое решение , чтобы увидеть, как предварительно заполнить данные с помощью WorkManager.

...