NullPointerException в конструкторе сервиса

В моем проекте Android у меня есть Service:

public class MyService extends Service{

    //I defined a explicite contructor 
    public MyService(){
       //NullPointerException here, why?
       File dir = getDir("my_dir", Context.MODE_PRIVATE);
    }

    @Override
    public void onCreate(){
      super.onCreate();
      ...
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);
        ...
    }

}

Я обычно знаю, я не должен явно определять конструктор для Android Service, Но в моем случае я хочу использовать конструктор для создания каталога во внутренней памяти.

Когда я пытаюсь это сделать, я получаю исключение NullPointerException, которое я не понимаю, почему? Может ли кто-нибудь объяснить мне причину, почему я получил NullPoineterException при вызове getDir(...) в моем явном конструкторе?

4 ответа

Решение

getDir() это метод в Context,

Служба не настроена для использования в качестве Context до тех пор onCreate(),

По сути, структура устанавливает службы (и действия в этом отношении) следующим образом:

  1. Создать объект
  2. Настройте Context с соответствующими ресурсами для текущей конфигурации
  3. Вызов onCreate() на объекте

Вы не можете делать ничего, что требует, чтобы объект был правильно настроен Context на шаге 1, т.е. во время инициализации переменной-члена или конструктора.

Вы должны использовать функцию жизненного цикла сервиса onCreate(). Функция onCreate запускается только один раз в жизненном цикле сервиса и работает как конструктор. Если вы хотите, чтобы он обновлялся в любом месте, вы можете поместить его в onStartCommand(намерение намерения, флаги int, int startId).

Как сказал @laalto, сервис не настроен для использования в качестве контекста, пока onCreate().

Так что сделайте одну глобальную переменную Context.

Context ctx;

Также сделать конструктор для вашего класса MyService должно быть.

public MyService(Context mContext){

   this.ctx = mContext;
   File dir = ctx.getDir("my_dir", Context.MODE_PRIVATE);
}

Вероятно, в вашем сервисном конструкторе Context все еще пусто, а getDir использует Context для своей внутренней работы. Вы можете проверить это в следующих источниках:

http://androidxref.com/4.4.2_r1/xref/frameworks/base/core/java/android/content/ContextWrapper.java#244

243    @Override
244    public File getDir(String name, int mode) {
245        return mBase.getDir(name, mode);
246    }

так что если mBase равен нулю, вы получите NPE

mBase будет установлен в конструкторе:

56    public ContextWrapper(Context base) {
57        mBase = base;
58    }

Служба расширяет ContextWrapper, но конструктор службы вызывает непосредственно этот конструктор со значением NULL:

http://androidxref.com/4.4.2_r1/xref/frameworks/base/core/java/android/app/Service.java#294

294    public Service() {
295        super(null);
296    }

поэтому вы должны дождаться Service.onCreate() или (если можете) использовать некоторый глобально известный контекст, например, из вашего объекта приложения.

Другие вопросы по тегам