Недавно мы преобразовали наш основной класс Application в Kotlin.
С тех пор у нас возникают сбои, особенно ночью (когда наше приложение, вероятно, было убито системой), когда запускается наш JobService.
Мы обращаемся к контексту приложения статическим способом для некоторых зависимостей, которые работали довольно хорошо, прежде чем мы преобразовали класс в Kotlin.С тех пор статическим геттером является lateinit var
, который инициализируется в функции приложения onCreate
.
После выпуска Google Play сообщил об этих сбоях:
Caused by: kotlin.UninitializedPropertyAccessException:
at x.y.z.application.App.access$getAppContext$cp
[...]
at x.y.z.jobs.JobSchedulerService.onCreate (JobSchedulerService.java:27)
Что приводит к вопросу, не выполнен ли наш Application.onCreate()
еще не выполнено?
Мы рефакторинг JobService aнемного, чтобы уменьшить количество статического доступа к контексту, пока не потребуется серьезный рефакторинг.После этого мы получили эти сбои от наших пользователей в консоли Google Play:
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)
Эти сбои говорят нам то же самое: Application.onCreate()
еще не был выполнен, поскольку Коин не инициализирован.
Итак, мой вопрос?Почему время выполнения Application.onCreate()
изменяется при преобразовании в Kotlin или почему наше приложение больше не создается до запуска JobService?
Я имею в виду, конечно, что мы могли бы реорганизовать все зависимости приложения, чтобы использовать контекстпредоставляется самим JobService, но что, если приложение будет создано впоследствии, и мы все еще хотим использовать Koin?Наше приложение, вероятно, снова вылетит с AlreadyStartetException
.И если наше приложение еще не «там», какой контекст будет иметь служба?
Источники (упрощенно):
Приложение
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;
}
}
Регистрация манифеста
<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);
...
}