This code is on a wearable. I need to create a service with custom constructor (I need to pass in another context). So I created and started the service this way:
Update 2 this part is in onCreate() of the calling activity (WearActivity).
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
HeartRateMonitorService service = new HeartRateMonitorService(WearActivity.this);
service.onCreate();
service.onStartCommand(null,0,123);
}
}, 5000);
Then in the onStartCommand function, I posted a delay Runnable to stop the service by stopSelf.
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int superResult = super.onStartCommand(intent, flags, startId);
//...other code
Handler handler = new Handler();
handler.postDelayed( stopServiceRunnable
, EXPIRY_TIME_IN_MILLIS);
return START_NOT_STICKY;
}
Runnable stopServiceRunnable = new Runnable() {
@Override
public void run() {
Log.d(TAG, "calling stopSelf()");
stopSelf();
}
};
The code did jump to inside the Runnable (by printing out the log line), however, it didn't jump to onDestroy(). Also, other tasks in the service keep performing and printing out logs (it is a heart rate monitoring service).
Any idea? Thanks.
Update: full source code file as required:
package com.marctan.hrmtest;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.wearable.MessageApi;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.Wearable;
import com.google.android.gms.wearable.WearableStatusCodes;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentLinkedQueue;
public class HeartRateMonitorService extends Service implements SensorEventListener {
private static final String TAG = "HRService";
private Sensor mHeartRateSensor;
private SensorManager mSensorManager;
// private CountDownLatch latch;
private static final int SENSOR_TYPE_HEARTRATE = 65562;
private int mStartId;
private static final String PATH = "MyHeart";
TimerTask timerTask;
private long mStartTime;
public static final long EXPIRY_TIME_IN_MILLIS = TimeUtils.InMillis.SECOND *20;
private static final long INTERVAL_TO_CHECK_CONNECTION_MILLIS = 3000 ;
GoogleApiClient googleApiClient;
Context mBaseConext;
private Timer mTimer;
ConcurrentLinkedQueue<HeartRate> queue;
public HeartRateMonitorService(Context context){
super();
mBaseConext = context;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
attachBaseContext(mBaseConext);
queue = new ConcurrentLinkedQueue<HeartRate>();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int superResult = super.onStartCommand(intent, flags, startId);
mStartId = startId;
Log.d(TAG, "prepare to call getSystemService");
mSensorManager = ((SensorManager)mBaseConext.getSystemService(SENSOR_SERVICE));
Log.d(TAG, "after calling getSystemService");
mHeartRateSensor = mSensorManager.getDefaultSensor(SENSOR_TYPE_HEARTRATE); // using Sensor Lib2 (Samsung Gear Live)
mSensorManager.registerListener(HeartRateMonitorService.this, mHeartRateSensor, 3);
mStartTime = System.currentTimeMillis();
googleApiClient = new GoogleApiClient.Builder(HeartRateMonitorService.this)
.addApi(Wearable.API)
.build();
googleApiClient.connect();
startActiveStateCheckingTimer();
Handler handler = new Handler();
handler.postDelayed( stopServiceRunnable
, EXPIRY_TIME_IN_MILLIS);
return START_NOT_STICKY;
}
/***/
private void startActiveStateCheckingTimer() {
if (mTimer == null) {
mTimer = new Timer();
timerTask = new CheckTask();
mTimer.scheduleAtFixedRate(timerTask, 0,
INTERVAL_TO_CHECK_CONNECTION_MILLIS);
}
}
Runnable stopServiceRunnable = new Runnable() {
@Override
public void run() {
mSensorManager.unregisterListener(HeartRateMonitorService.this);
Log.d(TAG, "calling stopSelf()");
stopSelf();
}
};
private class CheckTask extends TimerTask{
int localCount=0;
@Override
public void run() {
Log.d("SHORT_IN","count: "+ localCount );
fireMessageSimple();
localCount++;
}
}
public static class HeartRate {
private final int accuracy;
final int rate;
final long signature;
public HeartRate(int rate, long _sign, int accuracy) {
this.rate = rate;
this.signature= _sign;
this.accuracy = accuracy;
}
}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
//should get the time outside the queuing task to be precise
long timeStampMillis = System.currentTimeMillis();
QueuingTask task = new QueuingTask(queue,timeStampMillis, sensorEvent);
task.execute();
}
private void fireMessageSimple() {
// Send the RPC
PendingResult<NodeApi.GetConnectedNodesResult> nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient);
nodes.setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>() {
@Override
public void onResult(NodeApi.GetConnectedNodesResult result) {
for (int i = 0; i < result.getNodes().size(); i++) {
Node node = result.getNodes().get(i);
String nName = node.getDisplayName();
String nId = node.getId();
Log.d(TAG, "Node name and ID: " + nName + " | " + nId);
byte [] myBytes;
StringBuilder sBuidler = new StringBuilder();
Iterator<HeartRate> iter = queue.iterator();
int count=0;
while (iter.hasNext() && count <100 ){
HeartRate rate = iter.next();
sBuidler.append(rate.signature).append(",").append(rate.accuracy).append(",").append(rate.rate).append("\n");
iter.remove();
count++;
}
myBytes = sBuidler.toString().getBytes();
PendingResult<MessageApi.SendMessageResult> messageResult = Wearable.MessageApi.sendMessage(googleApiClient, node.getId(),
PATH, myBytes);
messageResult.setResultCallback(new ResultCallback<MessageApi.SendMessageResult>() {
@Override
public void onResult(MessageApi.SendMessageResult sendMessageResult) {
Status status = sendMessageResult.getStatus();
Log.d(TAG, "Status: " + status.toString());
if (status.getStatusCode() == WearableStatusCodes.SUCCESS) {
Log.d(TAG, "SENT SUCCESSFULLY !!!!!!!!!!!!!");
}
}
});
}
}
});
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
Log.d(TAG, "accuracy changed: " + i);
}
@Override
public void onDestroy() {
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
Log.d(TAG, "calling onDestroy");
super.onDestroy();
}
}