简体   繁体   中英

Android How to implement JobScheduler with Koin

I'm starting to use Koin as a service locator/DI due to it's simplicity to implement. I'm facing a issue regarding : Evernote Jobscheduler

As of now I have the following code:

class ForceUpdateJob : Job() {
const val TAG: String = "FORCE_UPDATE_JOB_TAG"

 fun scheduleJob() {
//Code
}
override fun onRunJob(params: Params): Result {
//Code
}

On my SplashViewModel I call all my jobs like this:

 private fun scheduleJobs() {
    if (JobManager.instance().getAllJobRequestsForTag(Sync1.TAG).isEmpty())
        Sync1.scheduleJob()

    if (JobManager.instance().getAllJobRequestsForTag(Sync2.TAG).isEmpty())
        Sync2.scheduleJob()

    if (JobManager.instance().getAllJobRequestsForTag(ForceUpdateJob.TAG).isEmpty())
        ForceUpdateJob.scheduleJob()
}

I have a job creator like this:

class MyJobCreator : JobCreator {

override fun create(tag: String): Job? = when (tag) {
    Sync1Job.TAG -> Sync1Job()
    Sync2Job.TAG -> Sync2Job()
    ForceUpdateJob.TAG -> ForceUpdateJob()
    else -> null
}
}

And on my App class I create the JobManager like this:

  JobManager.create(this).addJobCreator(MyJobCreator())

And it works perfectly, all my jobs are periodic and are scheduled every 15 minutes, everything runs and works fine. (This structure follows the instructions on the Jobscheduler github page)

But when starting using DI with Koin, the following changes have been made:

I have my module with all dependencies that I need:

val forceUpdateModule: Module = module {
bean { ForceUpdateDataSource() as ForceUpdateDataSourceInterface }
bean { ForceUpdateRepository(get()) as ForceUpdateRepositoryInterface }
factory { ForceUpdateWorker(get()) }
factory { ForceUpdateJob(get()) }
}

My Repository singleton instance is now passed by dependency for my Worker, and Worker is passed as a dependency for my update job:

class ForceUpdateJob(val forceUpdateWorker: ForceUpdateWorker) : Job() 

class ForceUpdateWorker(val repository: ForceUpdateRepositoryInterface)

So in order for this to work, I had to change my JobCreator class:

class MyJobCreator(private val forceUpdateJob: ForceUpdateJob) : JobCreator

And create a new module for this:

val jobSchedulerModule: Module = applicationContext {
factory { MyJobCreator(get()) }
}

The weird part comes on the AppCoordinator, I created a property and injected it:

So this:

 JobManager.create(this).addJobCreator(MyJobCreator())

Became this:

private val myJobCreator : MyJobCreator by inject()
JobManager.create(this).addJobCreator(myJobCreator)

And I start koin like this:

private fun initKoin() {
    startKoin(this,
            listOf(forceUpdateModule,
                    splashModule,
                    jobSchedulerModule))
}

And this indeed works for the first time. But when the job is rescheduled and tries to execute again, my app crashes with the following exception:

Job for tag FORCE_UPDATE_TAG was already run, a creator should always create a new Job instance

Any ideas on what am I missing?

Thanks in advance

I think your problem has to do with the fact that the job creator doesn't create jobs anymore.

The job creator must follow the factory design pattern, every time the you want to reschedule a job you must create a new instance of this job. So your MyJobCreator should only receive the necessary dependencies to create the jobs. Not the jobs themselfs.

So I would remove the koin factory of jobs, and make your MyJobCreator receive a factoryUpdateWorker and it would have a create method like this:

class MyJobCreator(val forceUpdateWorker: ForceUpdateWorker) : JobCreator

    override fun create(tag: String): Job? = when (tag) {
        Sync1Job.TAG -> Sync1Job()
        Sync2Job.TAG -> Sync2Job()
        ForceUpdateJob.TAG -> ForceUpdateJob(forceUpdateWorker)
        else -> null
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM