Trouble keeping Google Cloud Message alive
android, google-cloud-messaging, java
Solution
I actually solved this some time ago, Erik Z's recent comment remained me to post my solution.
I solved this by creating a recurring alarm that triggers a broadcast, which creates and broadcasts the intents. The gaps were caused by the original service being killed and then restarted as a result of the START_STICKY flag.
Here are the various parts (pulled from various files)
This was needed pre-kitkat at the very least, I don't know if it is still needed, I assume it is. I have not turned it off to confirm however.
The alarm manager, intent , and pending intent.
AlarmManager alarmManager = (AlarmManager) Context.getSystemService(Context.ALARM_SERVICE);
Intent gcmKeepAliveIntent = new Intent("com.gmail.npnster.ourlatitude.gcmKeepAlive");
PendingIntent gcmKeepAlivePendingIntent = PendingIntent.getBroadcast(mContext, 0, gcmKeepAliveIntent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, 4*60*1000, gcmKeepAlivePendingIntent);
The broadcast receiver:
public class GcmKeepAliveBroadcastReceiver extends BroadcastReceiver {
private GcmKeepAlive gcmKeepAlive;
@Override
public void onReceive(Context context, Intent intent) {
MyLog.p(this,"inside gcm keep alive receiver");
gcmKeepAlive = new GcmKeepAlive(context);
gcmKeepAlive.broadcastIntents();
}
}
The keep alive class that sends the keep alive broadcasts.
public class GcmKeepAlive {
protected Context mContext;
protected Intent gTalkHeartBeatIntent;
protected Intent mcsHeartBeatIntent;
public GcmKeepAlive(Context context) {
mContext = context;
gTalkHeartBeatIntent = new Intent(
"com.google.android.intent.action.GTALK_HEARTBEAT");
mcsHeartBeatIntent = new Intent(
"com.google.android.intent.action.MCS_HEARTBEAT");
}
public void broadcastIntents() {
MyLog.p(this,"sending heart beat to keep gcm alive");
mContext.sendBroadcast(gTalkHeartBeatIntent);
mContext.sendBroadcast(mcsHeartBeatIntent);
}
}
Problem
I am trying to work around the gcm time out issue, there are many threads on this subject, here is one for reference. A proposed workaround is to broadcast a pair of intents at an interval shorter than the tcp timeout. My implementation is to create a class that extends the CountDownTimer class and hold an instance of that class in an existing service. This derived class restarts itself when it is finished and the service is marked as STICKY_START, so once started, I would think it should just keep broadcasting the intents every 4 minutes, but for some reason there are gaps, when the counter does not broadcast the intents and I still loose contact with the GCM server. The two relevant classes are below. Can anyone explain and offer a solution as to why this strategy does not work? I created a class that extends CounDownTimer that should broadcast the intents every 4 minutes. ``` public class GcmKeepAlive extends CountDownTimer { protected CountDownTimer timer; protected Context mContext; protected Intent gTalkHeartBeatIntent; protected Intent mcsHeartBeatIntent; public GcmKeepAlive(Context context) { super(4*60* 1000,4*60*1000); mContext = context; gTalkHeartBeatIntent = new Intent("com.google.android.intent.action.GTALK_HEARTBEAT"); mcsHeartBeatIntent = new Intent("com.google.android.intent.action.MCS_HEARTBEAT"); System.out.println("stariing heartbeat countdown timer"); this.start(); } @Override public void onTick(long millisUntilFinished) { } @Override public void onFinish() { System.out.println("sending heart beat to keep gcm alive"); mContext.sendBroadcast(gTalkHeartBeatIntent); mContext.sendBroadcast(mcsHeartBeatIntent); this.start(); } } ``` here is the service in my app that holds an instance of the GcmKeepAlive class import android.app.Service; import android.content.Intent; import android.os.IBinder; ``` public class LocationMonitorService extends Service { private DeviceLocationClient deviceLocationClient; private GcmKeepAlive gcmKeepAlive; @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); System.out.println("creating the LocationMonitorService"); deviceLocationClient = new DeviceLocationClient(this); gcmKeepAlive = new GcmKeepAlive(this); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub System.out.println("inside service making request for location updates"); deviceLocationClient.requestLLocationUpdates(); gcmKeepAlive.start(); return START_STICKY; } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } } ``` Here is an example of a gap as seen in logcat. ``` 07-13 14:59:05.583 I/System.out(21651): sending heart beat to keep gcm alive 07-13 15:03:05.640 I/System.out(21651): sending heart beat to keep gcm alive 07-13 15:07:05.776 I/System.out(21651): sending heart beat to keep gcm alive 07-13 15:11:05.922 I/System.out(21651): sending heart beat to keep gcm alive 07-13 15:27:31.994 I/System.out(21651): sending heart beat to keep gcm alive ```