Reputation: 10540
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
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
Reputation: 134664
Why not call initMessenger()
in your onServiceConnected()
method? That way mService
is sure to be assigned.
Upvotes: 3
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