0

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();
    }
}
EyeQ Tech
  • 7,198
  • 18
  • 72
  • 126

1 Answers1

0

Just an hint, instead of use a runnable try to use an asyncTask as follow

 public class StopServiceTask extends AsyncTask<Void, Void, Void> {

    @Override
    protected Void doInBackground(final Void... params) {
        try {
            Thread.sleep(EXPIRY_TIME_IN_MILLIS);
        } catch (final InterruptedException e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    protected void onPostExecute(final Void result) {
        Log.d(TAG, "calling stopSelf()");
        stopSelf();
    }

 }

and call it where you are currently running your runnable

 new StopServiceTask()
            .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

Let me know if this work.

axl coder
  • 739
  • 3
  • 19
  • the problem is not runnable or asynctask, even with runnable, stopSelf() is still called. – EyeQ Tech Jul 28 '14 at 12:22
  • Can you post the code where you are starting the service? It could be that the service is continuously restarted. – axl coder Jul 28 '14 at 12:40
  • Maybe the problem is due to the timer inside your service (sorry, I'm guessing), try to cancel your TimerTask and your Timer inside stopServiceRunnable. – axl coder Jul 28 '14 at 13:41