4

In my Android project, I have a 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);
        ...
    }

}

I know normally, I shouldn't explicitly define a constructor for Android Service. But in my case, I want to use the constructor to create a directory in my internal storage.

When I try it, I got NullPointerException, which I don't understand why? Could anyone explain to me the reason why I got NullPoineterException when call getDir(...) in my explicite constructor ?

Leem.fin
  • 40,781
  • 83
  • 202
  • 354

4 Answers4

6

getDir() is a method in Context.

The service is not set up to be used as a Context until onCreate().

Basically, the framework sets up services (and activities for that matter) the following way:

  1. Create the object
  2. Set up the Context, with appropriate resources for the current configuration
  3. Call onCreate() on the object

You cannot do anything that requires the object to be a properly set up Context at step 1 i.e. during member variable initialization or constructor.

laalto
  • 150,114
  • 66
  • 286
  • 303
1

You have to use service lifecycle function onCreate(). onCreate function run only once in a service lifecycle and works as constructor. If you want it to update anywhere then you can put it in onStartCommand(Intent intent, int flags, int startId).

vaibhav kumar
  • 414
  • 2
  • 11
1

Probably Context is still null in your service constructor, and getDir is using Context for its internal workings. You can check it in following sources:

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    }

so if mBase is null then you will get NPE

mBase will be set in constructor:

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

Service extends ContextWrapper, but service constructor is calling directly this constructor with null value:

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

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

so you must wait for Service.onCreate(), or (if you can) use some globally known Context like from you aplication object.

marcinj
  • 48,511
  • 9
  • 79
  • 100
1

As @laalto said The service is not set up to be used as a Context until onCreate()..

So make one global variable of Context.

Context ctx;

Also make Constructor for your MyService class should be.

public MyService(Context mContext){

   this.ctx = mContext;
   File dir = ctx.getDir("my_dir", Context.MODE_PRIVATE);
}
Piyush
  • 18,895
  • 5
  • 32
  • 63
  • Does this mean I have to explicitely create a instance of my service by MyService myService = new MyService(getApplicationContext()) ? If so, when I start the service, does it use the same instance ? – Leem.fin Jan 13 '14 at 10:38
  • No..U haven't like this... you have to just use as new MyService(this); in your activity – Piyush Jan 13 '14 at 10:39
  • No, you don't get my question, I mean how could you guarantee when I start my service in activity, it will use this explicitely created instance? For example, I start service by : startService(new Intent(this, MyService.class)) , I need to use the instance created by new MyService(this), how can I guarantee this? – Leem.fin Jan 13 '14 at 10:42
  • No when you start your service using Intent then you don't need to it. But whenever you call our service and perform some task then you have to make a Context variable for it. And for more specification read what laalto said. – Piyush Jan 13 '14 at 10:46
  • Ok, then there will be at least 2 instances of MyService created. One is for calling the service to do tasks, the other is created by system when start service. This is not I'd like to have. But anyhow, thank you for making me clear. – Leem.fin Jan 13 '14 at 10:49