I have an Android application that uses a Remote Service and I bind to it with bindService()
, which is asynchronous.
The app is useless until the service is
When I need to wait a service to be bound before doing something else I play with locks. Precisely, the ServiceConnection
owns a lock object and exposes a waitUntilConnected
method that block on the lock until a wake up signal. That notification is located in the onServiceConnected
callback.
public class MyServiceConnection implements ServiceConnection {
private volatile boolean connected = false;
private Object lock = new Object();
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
connected = true;
synchronized (lock) {
lock.notifyAll();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
connected = false;
}
public void waitUntilConnected() throws InterruptedException {
if (!connected) {
synchronized (lock) {
lock.wait();
}
}
}
}
So, for example, if an activity has to wait a service to be bound, it calls simply the waitUntilConnected
method.
protected void onStart() {
super.onStart();
bindService(myServiceIntent, myServiceConnection, Context.BIND_AUTO_CREATE);
try {
myServiceConnection.waitUntilConnected();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
I placed the waitUntilConnected
method in onStart
just as an example, but it has to be called in a different thread. I'd like to hear a more elegant way! :)
It seems that there is a way to do this. KeyChain.java
and several Google-written classes uses a LinkedBlockingQueue
to allow synchronously bind to a service.
For example, see the method called bind
on this: https://github.com/android/platform_frameworks_base/blob/master/keystore/java/android/security/KeyChain.java
It seems to return the service object synchronously due to the use of blocking queue.
Unfortunately, as stated on the Android docs https://developer.android.com/reference/android/security/KeyChain.html, some methods throws InterruptedException
, due to the taking of element from the queue that may be interrupted when waiting.
You cannot have bindService() block. However, your ServiceConnection (2nd parameter to bindService) has callbacks to tell you when the service is connected and disconnected, so you can have other code block until your onServiceConnected() method unblocks it.
bindService()
cannot be made to block. That kind of defeats the whole purpose of a Service
. You said that you whole UI consists of results from the service. I think you need to rethink your UI and populate it with some kind of intermediate representation that shows the user that the app is gathering data.