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;
}
}
SearchState
public class SearchState extends State {
//Koin Crash in SearchState.<init>
private PlacemarkRepository placemarkRepository = get(PlacemarkRepository.class);
...
}
from JobScheduler JobService is startet without Application
No comments:
Post a Comment