Question

Take this base class:

public abstract class XMPPSubservice
{

    protected XMPPService mTheService;


    protected XMPPSubservice(Context context) 
    {
        Intent intent = new Intent(context, XMPPService.class);
        context.startService(intent);
    }


    public void onServiceInstance(XMPPService service) {
        // TODO Auto-generated method stub
        mTheService = service;
    }

}

And this derived class:

public class PublicDataSubservice extends XMPPSubservice 
{

    private final SomeObject mObj = new SomeObject();

    public PublicDataSubservice(Context context) {
        super(context);
    }

    @Override
    public void onServiceInstance(XMPPService service) 
    {
        super.onServiceInstance(service);
            mObj.doSomethingWith(mTheService);
    }

}

The goal was to only call mObj.doSomethingWith(mTheService); after the mTheService became valid (which happened in the base class). Thing was it always spat out NPE at the mObj line. I can understand why that happened, but it looks wonky to me. So is this a bug or a feature of DVM ? How about JVM ?

Was it helpful?

Solution

That's entirely correct, and would occur in "vanilla" Java too.

Instance variable initializers are only executed at the start of the constructor body after the superclass constructor has completed executing. So while the XMPPSubservice constructor is executing, mObj is null - you then call a virtual method from the constructor, and the override in PublicDataService executes.

Moral: don't call virtual methods from constructors, unless you really have to, in which case you should document them really carefully. (Very occasionally it's useful, but you should try hard to avoid it.) Basically it means you end up with a call on a potentially-partially-initialized object, which is what's happening here.

OTHER TIPS

I tried the following using stub implementations of your objects in a Java VM.

public static void main(String[] args) {
    Context context = new Context();
    PublicDataSubservice pds = new PublicDataSubservice(context);
    XMPPService service = new XMPPService();
    pds.onServiceInstance(service);
}

No NullPointerException.

Am I missing something? I guess that onServiceInstance must actually get called as a result of context.getService(intent)?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top