Using RoboSpice in IntentService. Solved the problem with help of CountDownLatch. Let's say we have 2 different SpiceManagers and some syncMethods to execute in sequence in the IntentService.
Globals:
private final SpiceManager aSpiceManager =
new SpiceManager(ASpiceService.class);
private final SpiceManager bSpiceManager =
new SpiceManager(BSpiceService.class);
private CountDownLatch handleIntentLatch;
onHandleIntent: Before we execute syncMethodA - we init our CountDownLatch with 1. After executing syncMethodA we await() for countDown() on our latch. When later some method will call countDown() on our latch at least once - method onHandleIntent will continue it's execution and finish which will trigger IntentService onDestroy() callback.
@Override
protected void onHandleIntent(Intent intent) {
handleIntentLatch = new CountDownLatch(1);
syncMethodA();
try {
handleIntentLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
syncMethodA():
Suppose we need to launch some sync methods in sequence (syncMethodA which callback executes syncMethodB etc).
private void syncMethodA() {
SpiceRequest requestA = new SpiceRequest();
if (!aSpiceManager.isStarted()) {
LogUtils.LOGD(TAG, "starting aSpiceManager");
aSpiceManager.start(getApplicationContext());
}
aSpiceManager.execute(requestA , new RequestListener<ResponseA>() {
@Override
public void onRequestSuccess(final ResponseA responseA) {
// SOME LOGIC
syncMethodB();
// SOME LOGIC
@Override
public void onRequestFailure(SpiceException spiceException) {
handleIntentLatch.countDown();
// SOME LOGIC
}
});
}
syncMethodB, syncMethodC etc are the same - in onRequestSuccess we start next syncMethodX. In on onRequestFailure we countDown() our latch (handleIntentLatch).
Very important!!!
In last syncMethodX in sequence (after which completion we want onHandleIntent method to continue it's execution and finish which will result IntentService to stop) - we countDown() our latch in onRequestSuccess ALSO.
onDestroy: here we stop our SpinceManagers.
@Override
public void onDestroy() {
super.onDestroy();
LogUtils.LOGD(TAG, "onDestroy");
shutDownSpiceManagers();
}
shutDownSpiceManagers:
private void shutDownSpiceManagers() {
if (aSpiceManager.isStarted()) {
LogUtils.LOGD(TAG, "stopping aSpiceManager");
aSpiceManager.shouldStop();
}
if (bSpiceManager.isStarted()) {
LogUtils.LOGD(TAG, "stopping bSpiceManager");
bSpiceManager.shouldStop();
}
}
All should be OK now: no leaked Context, SpiceManagers will be killed in onDestroy AND ONLY AFTER callbacks are resolved.