I have an Activity calling a Service defined in IDownloaderService.aidl:
public class Downloader extends Activity {
IDownloaderService downloader = null;
//
*The basic idea is same with @18446744073709551615, but I will share my code as well.
As a answer of main question,
But what should I do to right use this service after bindService succeeds?
[Original expectation (but not work)]
wait until service connected like below
@Override
protected void onStart() {
bindService(service, mWebServiceConnection, BIND_AUTO_CREATE);
synchronized (mLock) { mLock.wait(40000); }
// rest of the code continues here, which uses service stub interface
// ...
}
It won't work because both bindService()
in onCreate()/onStart()
and onServiceConnected()
is called at same main thread.
onServiceConnected()
is never called before wait finishes.
[Alternative solution]
Instead of "wait", define own Runnable to be called after Service Connected and execute this runnable after service connected.
Implement custom class of ServiceConnection as follows.
public class MyServiceConnection implements ServiceConnection {
private static final String TAG = MyServiceConnection.class.getSimpleName();
private Context mContext = null;
private IMyService mMyService = null;
private ArrayList runnableArrayList;
private Boolean isConnected = false;
public MyServiceConnection(Context context) {
mContext = context;
runnableArrayList = new ArrayList<>();
}
public IMyService getInterface() {
return mMyService;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.v(TAG, "Connected Service: " + name);
mMyService = MyService.Stub.asInterface(service);
isConnected = true;
/* Execute runnables after Service connected */
for (Runnable action : runnableArrayList) {
action.run();
}
runnableArrayList.clear();
}
@Override
public void onServiceDisconnected(ComponentName name) {
try {
mMyService = null;
mContext.unbindService(this);
isConnected = false;
Log.v(TAG, "Disconnected Service: " + name);
} catch(Exception e) {
Log.e(TAG, e.toString());
}
}
public void executeAfterServiceConnected(Runnable action) {
Log.v(TAG, "executeAfterServiceConnected");
if(isConnected) {
Log.v(TAG, "Service already connected, execute now");
action.run();
} else {
// this action will be executed at the end of onServiceConnected method
Log.v(TAG, "Service not connected yet, execute later");
runnableArrayList.add(action);
}
}
}
And then use it in the following way (in your Activity class or etc),
private MyServiceConnection myServiceConnection = null;
@Override
protected void onStart() {
Log.d(TAG, "onStart");
super.onStart();
Intent serviceIntent = new Intent(getApplicationContext(), MyService.class);
startService(serviceIntent);
myServiceConnection = new MyServiceConnection(getApplicationContext());
bindService(serviceIntent, myServiceConnection, BIND_AUTO_CREATE);
// Instead of "wait" here, create callback which will be called after service is connected
myServiceConnection.executeAfterServiceConnected(new Runnable() {
@Override
public void run() {
// Rest of the code comes here.
// This runnable will be executed after service connected, so we can use service stub interface
IMyService myService = myServiceConnection.getInterface();
// ...
}
});
}
It worked for me. But there may be more better way.