telkins
telkins

Reputation: 10540

Service is not initialized, returns NullPointerException

I am trying to get two-way communication between my Service and Activity set up. To do this, I start my Service like normal, send a Message with the replyTo set to the Messenger in my Activity, and send it to my Service. That way I have a reference to send messages in both directions. Here is some relevant code in my Activty:

private Messenger mService = null;
private final Messenger mMessenger = new Messenger(new IncomingHandler());

private ServiceConnection mConnection = new ServiceConnection()
{
    public void onServiceConnected(ComponentName className, IBinder service)
    {
        mService = new Messenger(service);
        mBound = true;
    }

    public void onServiceDisconnected(ComponentName className)
    {
        mService = null;
        mBound = false;
    }
};

private void initMessenger()
{
    Message messageHandler = Message.obtain(null, NetworkService.MSG_GET_HANDLER, 0, 0);
    messageHandler.replyTo = mMessenger; //Set the replyTo to give a reference
    try
    {
        mService.send(messageHandler);
    }
    catch(RemoteException e)
    {
        e.printStackTrade();
    }
    catch(NullPointerException e)
    {
        e.printStackTrace(); //Why!!!
    }
}

public void onCreate()
{
...
    //Create the intent to start the network service
    Intent iService = new Intent(this, NetworkService.class);
    int[] connectionConfig = {CONNECTION_BT};
    iService.putExtra(CONNECTION_CONFIG, connectionConfig);
    bindService(iService, mConnection, Context.BIND_ABOVE_CLIENT);
    startService(iService);
    initMessenger();
}

A NullPointerException is thrown when I try to call mService.send(), most likely because mService is null at the time. If I move the initMessenger() code inside a Button's OnClickListener it works fine which is where the confusion comes in. Am I supposed to wait a certain amount of time after starting a Service to use it?

Upvotes: 1

Views: 2587

Answers (3)

Graeme
Graeme

Reputation: 25864

mService being null at this stage suggests that by this time your Service has not (yet) called onServiceConnected().

Unfortunately the documentation doesn't suggest there would be a gap between bindService() returning and the method in the ServiceConnection being called.

Infact, bindService() should return true when the Service has been started meaning once the code passes this stage the Service should either be started or not. Therefore I would check if bindService() has returned true or not before calling initMessenger() as it's possible the Service has failed to start correctly.

It's also possible that the code within onServiceConnected() is throwing an exception (which, since it is possible it's being called on a worker thread, could not cause your app to crash), you may want to check back in your log's to check if this is the case.

Also, startService(iService); is redundant in this context, bindService() starts the Service, calling startService on the service simply send's it a message.

Upvotes: 2

Kevin Coppock
Kevin Coppock

Reputation: 134664

Why not call initMessenger() in your onServiceConnected() method? That way mService is sure to be assigned.

Upvotes: 3

dymmeh
dymmeh

Reputation: 22306

Yes. You should only use the service once you know you are bound to it. Because you are trying to use your service immediately after attempting to bind to it you are not guaranteeing that you will be connected to the service. Sometimes the service may bind immediately so you won't get a crash. Sometimes it will take a bit longer so your call to initMessenger() will result in your NPE since the service has yet to connect.

Moving your initMessenger() call to your button click is allowing your service time to bind. Additionally, you should be checking to make sure you are bound (even if you give it time) since binding could potentially fail

Upvotes: 1

Related Questions