michael
michael

Reputation: 3945

Android repeated Service - onCreate called once, onStartCommand called many

I followed the basic android documentation to implement a Service, triggered repeatedly by AlarmManager every 40 seconds. Inside the service I register GPS listener, and if I don't get fix within 30 seconds I call stopSelf(), this in order to avoid 2 "concurrent" services running together. However if I do have fix within less then 30 seconds, I perform some logic and after I done I call stopSelf() - Assuming it all will take less then 40 seconds so again I have no issues of "concurrent" services running...

When I log print the order of execution of various Service methods it doesn't make any sense:

  1. onCreate is called only once, while onStartCommand is triggered every 40 seconds.
  2. The GPS is never fixed, maybe the fact that the hosting Activity also registered and do have GPS fix interfere here? (I testing outdoors and the activity does get fix)

This is my implementation - Pretty much straightforward googles android documentation:

public class DirectionService extends Service implements Constants {

private LocationManager mLocationManager;
private LocationListener mLocationListeners;
private Context mContext;
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;

@Override
public IBinder onBind(Intent arg0) {
    return null;  //not binding
}

@Override
public void onCreate() {
    HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
    mContext = getApplicationContext();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    //For each start request, send a message to start a job and deliver the start ID so we know which request we're stopping when we finish the job
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    mServiceHandler.sendMessage(msg);
    return START_STICKY;
}

//Handler that receives messages from the thread
private final class ServiceHandler extends Handler {

    public ServiceHandler(Looper looper) {
        super(looper);
    }

    /**
     * The real work done after we have (first) fixed location and from there we stop the service.
     * Therefore we pass the start id.
     */
    @Override
    public void handleMessage(final Message msg) {
        if (mLocationManager == null) {
            mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
            mLocationListeners = new LocationListener(msg.arg1);
        }
        try {
            mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_UPDATE_TIME, 0, mLocationListeners);
            mLocationManager.addGpsStatusListener(mGPSStatusListener);
        } catch (Exception e) {
            stopSelf(msg.arg1);
        }
        //Start timer for GPS to get fix location. Else we might have new concurrent instance of service
        new CountDownTimer(30000, 15000) {

            public void onTick(long millisUntilFinished) {}

            public void onFinish() {
                stopSelf(msg.arg1);
            }

        }.start();
    }

}

GpsStatus.Listener mGPSStatusListener = new GpsStatus.Listener() {
    public void onGpsStatusChanged(int event) {
        switch (event)
        {
            case GpsStatus.GPS_EVENT_FIRST_FIX:
                if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                        || ContextCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                    if (mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) != null) {
                        isGpsFixed = true;
                    }
                }
                break;
            default:
                break;
        }
    }
};

private class LocationListener implements android.location.LocationListener {

    private int startId;

    public LocationListener(int startId) {
        this.startId = startId;
    }

    @Override
    public void onLocationChanged(Location location) {
        if (isGpsFixed == true && location.getLongitude() != 0.0 && location.getLatitude() != 0.0 && isAlreadySentToCheck == false) {
            isAlreadySentToCheck = true;
            startLogic(startId);
        }
    }
    @Override
    public void onProviderDisabled(String provider) {}
    @Override
    public void onProviderEnabled(String provider) {}
    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {}
}

private void startLogic(final int startId) {
    //...
    stopSelf(startId);
}

@Override
public void onDestroy() {
    super.onDestroy();
    if (mLocationManager != null) {
        try {
            mLocationManager.removeUpdates(mLocationListeners);
        } catch (Exception ex) {}
    }
}

Upvotes: 0

Views: 1090

Answers (1)

raj
raj

Reputation: 2088

your service running many time because of start_sticky

if your service is killed by Android due to low memory, and Android clears some memory, then...

STICKY: ...Android will restart your service, because that particular flag is set.

NOT_STICKY: ...Android will not care about starting again, because the flag tells Android it shouldn't bother.

REDELIVER_INTENT: ...Android will restart the service AND redeliver the same intent to onStartCommand() of the service, because, again, of the flag.

suggest to your start_not_sticky

Upvotes: 2

Related Questions