RoomDB в JobSchedulerService

Недавно я добавил JobScheduler в свое приложение через JobService. Я использую JobService для периодической синхронизации с моей базой данных в фоновом режиме и обновления локального экземпляра Room DB.

Однако я вижу произвольные сбои с ошибкой:

Процесс: com.application.name, PID: 27229 java.lang.RuntimeException: невозможно создать экземпляр службы com.application.name.Services.SyncService: java.lang.NullPointerException: попытка вызвать виртуальный метод android.content.Context android. content.Context.getApplicationContext () 'для ссылки на нулевой объект

Полная трассировка стека выглядит следующим образом:

Вызвано java.lang.NullPointerException: попытка вызвать виртуальный метод android.content.Context android.content.Context.getApplicationContext () для ссылки на нулевой объект в com.application.name.Database.AppDatabase.getDatabase (AppDatabase.java : 38) в com.application.name.Services.SyncService. (SyncService.java:48) в java.lang.Class.newInstance (Class.java) в android.app.ActivityThread.handleCreateService (ActivityThread.java:3551) в android.app.ActivityThread.-wrap4 (Неизвестный источник) в android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1778) в android.os.Handler.dispatchMessage (Handler.java:105) в android.os.Looper .loop (Looper.java:164) в android.app.ActivityThread.main (ActivityThread.java:6798) в java.lang.reflect.Method.invoke (Method.java) в com.android.internal.os.Zygote $ MethodAndArgsCaller.run (Zygote.java:240) на com.android.internal.os.ZygoteInit. main (ZygoteInit.java:767)

Оскорбительная строка, выделенная в отчете о сбое, - это создание экземпляра Room DB в конструкторе JobService.

 public SyncService() {
        super();
        database = AppDatabase.getDatabase(getApplication());
    }

и в комнате DAO у меня есть следующий код:

private static AppDatabase INSTANCE;
public static AppDatabase getDatabase(final Context context){
        if(INSTANCE == null) {
            synchronized (AppDatabase.class){
                if(INSTANCE == null){

                    // Migration definitions go here
                    ..
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                            AppDatabase.class, context.getResources().getString(R.string.database))
                            .allowMainThreadQueries()
                            .addMigrations(FROM_2_TO_3)
                            .build();
                }
            }
        }
        return INSTANCE;
    }

Итак, я думаю, что понимаю, почему это происходит - когда приложение не работает, контекст приложения равен нулю, поэтому построитель базы данных Room сталкивается с проблемами при настройке.

Я хотел бы знать, есть ли способ получить доступ к моей базе данных Room DB, когда приложение не запущено. Передача контекста в инициализацию из JobService и написание вторичного конструктора кажется уродливым приемом, который может привести к непредсказуемым условиям, поэтому мне интересно, какие еще варианты у меня есть.

Я мог бы записать данные, полученные из JobService, в SharedPreferences, а затем синхронизировать их с БД при запуске приложения. Есть ли другой способ?


person kilokahn    schedule 22.12.2018    source источник
comment
Небольшая услуга: в будущем, вместо того, чтобы публиковать только сообщение об ошибке, публикуйте всю трассировку стека.   -  person CommonsWare    schedule 22.12.2018
comment
@CommonsWare: я добавил полную трассировку стека. Извините за ошибку. Между прочим, большой фанат. Вы помогли мне больше раз, чем вы думаете, своими ответами и идеями по другим вопросам. :)   -  person kilokahn    schedule 22.12.2018
comment
Я добавил полную трассировку стека - спасибо! Это примерно то, что я ожидал из вашего описания. Однако время от времени трассировка стека показывает то, чего автор вопроса не ожидал, поэтому в таких случаях помогает наличие полной трассировки. Ваша ошибка довольно странная, поскольку подразумевает, что getApplication() на JobService может иногда возвращать null, что беспокоит. Тем не менее, ваше решение - хороший первый шаг, и я наполовину его написал, когда вы опубликовали свое собственное. Кстати, большой фанат - спасибо за добрые слова!   -  person CommonsWare    schedule 22.12.2018
comment
Тем не менее, ваше решение - хороший первый шаг - спасибо за вашу поддержку и поддержку. Я буду продолжать ковыряться в приложении в течение следующих нескольких дней, и если увижу что-нибудь новое или любопытное, я добавлю сюда обновление. :)   -  person kilokahn    schedule 22.12.2018
comment
Привет, я довольно много работал над своим приложением и вижу довольно частое повторение с NPE в getApplicationContext () или getApplication () или 'this'. Любые указания о том, как этого избежать, было бы здорово!   -  person kilokahn    schedule 20.01.2019
comment
Я рекомендую вам задать новый вопрос с обновленным кодом и трассировкой стека, возможно, со ссылкой на этот вопрос, чтобы указать на предыдущую проблему и решение.   -  person CommonsWare    schedule 20.01.2019
comment
Сделаю! Большое спасибо!   -  person kilokahn    schedule 20.01.2019


Ответы (2)


Думаю, я упустил один простой факт: служба - это контекст.

Вместо прохождения:

 database = AppDatabase.getDatabase(getApplication());

все, что мне нужно было сделать, это вот что:

 database = AppDatabase.getDatabase(this);

Пока у меня не было повторяющихся сбоев ... пока. Я все еще открыт для других ответов, так что поделитесь своими взглядами, если вы думаете, что я могу сделать это лучше.

person kilokahn    schedule 22.12.2018
comment
Можете сказать, где вы назвали это заявление в сервисе? В onCreate или где? - person Harry .Naeem; 28.09.2019
comment
Вы можете использовать this где угодно внутри класса, расширяющего JobService, для доступа к контексту. - person Stephen Emery; 11.03.2020

applicationContext следует вызывать после вызова onCrate() метода. Следовательно, вам нужно запустить свой код внутри onCreate() метода.

person Ramin Ar    schedule 14.03.2021