Reputation: 838
I have used the Alarm Manager to allow the user to schedule a certain task to repeat at a certain amount of time. In the context of the application, I have an Android game where people are able to schedule when to send their ships. The Alarm Manager is working fine, alarms get kicked off at the right time etc.
What happens when an alarm is fired off (usually every hour and a bit), is that my IntentService will start communicating with the server to send the ships. This action may take 1 minute, but it can last up to 10 minutes. Even this all works fine. Alarms get fired, ships get sent, everyone happy. The problem arises at night, I go to sleep and expect when waking up that my ships have been sent all night long. Nope. Logging & notifications show that the Alarms are fired correctly, but it appears that the IntentService is killed when it's communicating with the server.
Possible cause for this is that I'm not looking at the game every once in a while like I do when I'm awake, and thus keep some form of process running which prevents the IntentService from being garbage collected.
I've already tried a LOT of things to fix this. I used to work with a BroadCastReceiver, I used to spawn ASyncTasks in the IntentService, but I've since refactored my code to not use those things anymore as they're bad practice for Services.
I have also checked this resource: http://techtej.blogspot.com.es/2011/03/android-thread-constructspart-4.html but I'm still not sure if what I'm doing is the correct thing to handle this situation. I have placed some extensive logging for the next night to review in the morning but I'd like you guys' opinion over this.
Oh I'm also requesting a WakeLock for the complete duration of the onHandleIntent function using:
PowerManager pm = (PowerManager) c.getSystemService(Context.POWER_SERVICE);
this.wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "MyApplicationWakeLock");
My IntentService:
public class ScheduledRequestService extends IntentService {
public ScheduledRequestService() {
super("ScheduledRequestService");
}
@Override
public int onStartCommand(Intent intent, int flags, int startID){
Logger.d("OnStartCommand!");
return super.onStartCommand(intent, flags, startID);
}
@Override
protected void onHandleIntent(Intent intent) {
ScheduledRequest request = (ScheduledRequest) intent.getExtras().getSerializable("request");
// This function will start a lot of client <-> server communication
request.onExecute(this, intent);
}
@Override
public void onDestroy(){
Logger.d("OnDestroy!");
super.onDestroy();
}
}
So again, my question is; am I structuring this correctly? Should I use a normal Service instead of an IntentService ? Can my IntentService get garbage collected while it is handling an Intent (I think I read that this is possible)?
Upvotes: 1
Views: 1095
Reputation: 838
Turns out the error was somewhere else than the garbage collector of Android. I was using cache which eventually led to me 'running out of ships' because on send time, it deducted the sent amount of ships from the pool. When they returned however, they were never added back to the cache. During the day I probably manually refreshed the cache or forced Android to clear it by using my phone otherwise which didn't cause the problem to arise (as much).
Upvotes: 0
Reputation: 1007534
Can my IntentService get garbage collected while it is handling an Intent (I think I read that this is possible)?
No, but your process can be terminated.
am I structuring this correctly?
Not if you are trying to use a _WAKEUP
alarm. You need to set things up more carefully in that case, and I would recommend either WakefulBroadcastReceiver
or my WakefulIntentService
to handle that pattern.
Should I use a normal Service instead of an IntentService ?
No, an IntentService
will be fine. You may need to consider making it a foreground service using startForeground()
.
Upvotes: 1