Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JobScheduler JobService is started without Application

Tags:

We converted our main Application class to Kotlin recently.
Since then we are experiencing crashes, especially during the night (when our application was probably killed by the system), when our JobService is startet.

We are accessing the Application Context in a static way for some dependencies which worked pretty well before we converted the class to Kotlin. Since then the static getter is a lateinit var which is initialised in the applications onCreate function.

After the release Google Play reported these crashes:

Caused by: kotlin.UninitializedPropertyAccessException:    at x.y.z.application.App.access$getAppContext$cp    [...]   at x.y.z.jobs.JobSchedulerService.onCreate (JobSchedulerService.java:27)   

Which leads to the question, is our Application.onCreate() not executed yet?

We refactored the JobService a little bit to reduce the amount of static context access until a major refactoring would be necessary. After that, we received these crashes from our users in Google Play Console:

Caused by: kotlin.UninitializedPropertyAccessException:    at org.koin.standalone.StandAloneContext.getKoinContext (StandAloneContext.java:45)   at org.koin.java.standalone.KoinJavaComponent.get (KoinJavaComponent.java:66)   at org.koin.java.standalone.KoinJavaComponent.get$default (KoinJavaComponent.java:64)   at org.koin.java.standalone.KoinJavaComponent.get (KoinJavaComponent.java)   at x.y.z.SearchState.<init> (SearchState.java:21)   [...]   at x.y.z.jobs.JobSchedulerService.onStartJob (JobSchedulerService.java:54) 

These crashed tell us the same thing: Application.onCreate() was not executed yet because Koin is not initialised.

So my question? Why would the execution time of Application.onCreate() change when converting to Kotlin or why is our Application not created anymore before the JobService is startet?

I mean, sure, we could refactored the whole application dependencies to use the context provided by the JobService itself, but what if the application is created afterwards and we still want to use Koin? Our app will probably crash again with an AlreadyStartetException. And if our Application is not "there" yet, what context would the service have?

Sources (simplified):

Application

abstract class App : MultiDexApplication() {      companion object {         @JvmStatic         lateinit var appContext: Context         @JvmStatic         val isDevelopment: Boolean = BuildConfig.DEBUG     //  @JvmStatic     //  val isDevelopment: Boolean by lazy {      //      appContext.resources.getBoolean(R.bool.isDevelopment)      //  }     }      override fun onCreate() {         super.onCreate()          appContext = applicationContext         startKoin(                 applicationContext,                 listOf(                         coreModule,                         sharedPrefsModule                 )         )      } } 

JobService

public class JobSchedulerService extends JobService implements OnFinishListener {      @Override     public boolean onStartJob(JobParameters params) {          if (App.isDevelopment()) { //First crash cause `isDevelopment` relied on App.appContext             ...         }         this.mJobParameters = params;          this.mStateMachine = StateContext.getInstance(getApplication());         mStateMachine.setOnFinishListener(this);         mStateMachine.execute("" + params.getJobId()); //Second crash is in the first executed state auf this state Machine          return true;     } } 

Manifest Registration

    <service         android:name="x.y.z.jobs.JobSchedulerService"         android:enabled="true"         android:exported="true"         android:permission="android.permission.BIND_JOB_SERVICE">     </service> 

SearchState

public class SearchState extends State {      //Koin Crash in SearchState.<init>     private PlacemarkRepository placemarkRepository = get(PlacemarkRepository.class);      ... } 
like image 418
marilion91 Avatar asked Sep 14 '18 08:09

marilion91


People also ask

What is the use of JobScheduler in Android?

JobScheduler is introduced while the Android set limitation on background Execution. It means that the system will automatically destroy the background execution to save battery and memory. So if you want to perform some background job like some network operations no matter your app is running or not.

What is JobService?

android.app.job.JobService. Entry point for the callback from the JobScheduler . This is the base class that handles asynchronous requests that were previously scheduled. You are responsible for overriding JobService#onStartJob(JobParameters) , which is where you will implement your job logic.

What is on start job called?

OnStartJob is called by the Android system when it starts your job. However, onStopJob is only called if the job was cancelled before being finished (e.g. we require the device to be charging, and it gets unplugged).

What is JobScheduler API?

The JobScheduler API helps schedule background tasks that are executed in your application.


1 Answers

Job-service must have its own separate context, but i think you should try upgrading to WorkManager, as Job-service will not work on Android O and Later devices. Work manager is a new thing, but remember, minimum interval it will allow to execute job is 15 minutes.

like image 133
Sandip Savaliya Avatar answered Oct 18 '22 11:10

Sandip Savaliya