How to fix Service Instance Issue?

I am starting a service based on Alarm Manager in every 20 seconds which sends GPS data to my server. The problem is my heap and allocated heap size goes on increasing. When I analysed the heap dump, I found the number of service instances is equal to the number of calls to startService() . How to avoid this issue?


    public class SystemBootListener extends BroadcastReceiver {

  // Restart service every 30 seconds
  private static final long REPEAT_TIME = 1000 * 10;

  @Override
  public void onReceive(Context context, Intent intent) {

    Intent i = new Intent(context, StartLocationServiceAfterReboot.class);
    PendingIntent pending = PendingIntent.getBroadcast(context, 0, PendingIntent.FLAG_UPDATE_CURRENT);

    // Start 20 seconds after boot completed - so that all providers are initialized by then
    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.SECOND, 20);

    // Trigger every 10 seconds
    // InexactRepeating allows Android to optimize the energy consumption
    AlarmManager service = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    service.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), REPEAT_TIME, pending);
  }
} 


    public class StartLocationServiceAfterReboot extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {

      if(AppSettings.isRouteConfigured(context)){
          AppSettings.setServiceRunning(context, Boolean.TRUE);
          Intent service = new Intent(context, GPSComputationService.class);
          context.startService(service);
          }
  }
} 

public class GPSComputationService extends Service {

  private static final int MAX_TIME_TO_FETCH_NEW_LOCATION = 8000;

  private final IBinder mBinder = new ServiceBinder();

  private Timer timerToFetchLocInfoFromProviders = null;

  private LocationManager locationManager = null;

  private boolean gpsProviderEnabled=false;

  private boolean networkProviderEnabled=false;

  private int numberOfSatellites = 0;

  private GPSData bestKnownLocation = new GPSData();


  private TCPWriter tcpWriter  ;


  @Override
public void onCreate() {
    // TODO Auto-generated method stub
    super.onCreate();
    tcpWriter= new TCPWriter(this);
}

@Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    /*tcpWriter= new TCPWriter(this);*/
    computeBestLocation();
    return Service.START_STICKY;
  }

 private void stopGPSComputationService(){
        stopSelf();
    }


  @Override
  public IBinder onBind(Intent arg0) {
    return mBinder;
  }

  public class ServiceBinder extends Binder {
      public GPSComputationService getService() {
      return GPSComputationService.this;
    }
  }


  public GPSData getBestKnownLocation() {
      return bestKnownLocation;
    }

  public void publishBestKnownLocation(GPSData bestKnownLocation) {
        this.bestKnownLocation = bestKnownLocation;
        sendBestKnownLocationToNMEAServer();

    }


  public void sendBestKnownLocationToNMEAServer(){

      if(getBestKnownLocation() == null){
          stopGPSComputationService();
          return;
      }

      TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
      telephonyManager.getDeviceId();

      NMEAData dataPacketToWrite = new NMEAData(
              telephonyManager.getDeviceId(),
              getBestKnownLocation().getLatitude(),
              getBestKnownLocation().getLongitude(),
              getBestKnownLocation().getTimeStamp(),
              getBestKnownLocation().getSpeed(),
              getBestKnownLocation().getNumberOfSatellites()
              );

      tcpWriter.sendMessage(NMEAServerTypes.MVT600, 
              dataPacketToWrite);
      stopGPSComputationService();
  }



  public GPSData computeBestLocation()   {
      Log.d("#############GPSComputation Status", "Running.......");

        try{
                 if(locationManager==null)
                  locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);

                 //Add status listener for satellite count
                 locationManager.addGpsStatusListener(gpsStatusListener);


                 Criteria criteria = new Criteria();
                 criteria.setSpeedRequired(true);
                 criteria.setBearingRequired(true);
                 List<String> providers = locationManager.getProviders(criteria, false);


                //Capture if the GPS/Network providers have been disabled.
                try{
                    gpsProviderEnabled=providers.contains(LocationManager.GPS_PROVIDER) && 
                            locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
                }catch(Exception e){

                }

                try{
                    networkProviderEnabled=providers.contains(LocationManager.NETWORK_PROVIDER) && 
                            locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
                }catch(Exception e){

                }

                if(!gpsProviderEnabled && !networkProviderEnabled)
                    return null;

                if(gpsProviderEnabled)
                    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);

                if(networkProviderEnabled)
                    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);

                timerToFetchLocInfoFromProviders=new Timer();
                timerToFetchLocInfoFromProviders.schedule(new GetLastKnownGoodLocation(), MAX_TIME_TO_FETCH_NEW_LOCATION);
                locationManager.removeGpsStatusListener(gpsStatusListener);

                //Finally store the data in backend Service
                return getBestKnownLocation() ;

        }catch(Exception e){

            return null;
        }
    }

    LocationListener locationListenerGps = new LocationListener() {
        public void onLocationChanged(Location location) {
            timerToFetchLocInfoFromProviders.cancel();
            publishBestKnownLocation(extractAllGeoInfFromLocation(location));
            locationManager.removeUpdates(this);
            locationManager.removeUpdates(locationListenerNetwork);
            locationManager.removeGpsStatusListener(gpsStatusListener);
            gpsStatusListener = null;
        }

        public void onProviderDisabled(String provider) {

        }
        public void onProviderEnabled(String provider) {

        }
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }
    };


  //listen for gps status changes to capture number of satellites.
    GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() {
        @Override
        public void onGpsStatusChanged(int event) {
            if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS || event == GpsStatus.GPS_EVENT_FIRST_FIX) {
                GpsStatus status = locationManager.getGpsStatus(null);
                Iterable<GpsSatellite> sats = status.getSatellites();
                // Check number of satellites in list to determine fix state
                int tempNumberOfSatellites = 0;
                for (GpsSatellite sat : sats) {
                    if(sat.usedInFix())
                        tempNumberOfSatellites++;
                }
                numberOfSatellites = tempNumberOfSatellites;

            }
        }
    };


    LocationListener locationListenerNetwork = new LocationListener() {
        public void onLocationChanged(Location location) {


            timerToFetchLocInfoFromProviders.cancel();
            publishBestKnownLocation(extractAllGeoInfFromLocation(location));
            locationManager.removeUpdates(this);
            locationManager.removeUpdates(locationListenerGps);
        }

        public void onProviderDisabled(String provider) {

        }
        public void onProviderEnabled(String provider) {

        }
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }
    };

    class GetLastKnownGoodLocation extends TimerTask {
        @Override
        public void run() {
             locationManager.removeUpdates(locationListenerGps);
             locationManager.removeUpdates(locationListenerNetwork);

             Location bestKnownNetworkLocation = null, bestKnownGPSLocation=null;

             if(gpsProviderEnabled)
                 bestKnownGPSLocation=locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
             if(networkProviderEnabled)
                 bestKnownNetworkLocation=locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

             if(bestKnownGPSLocation!=null && bestKnownNetworkLocation!=null){
                 if(bestKnownGPSLocation.getTime()>bestKnownNetworkLocation.getTime())
                     publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownGPSLocation));
                 else
                     publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownNetworkLocation));
                 return;
             }

             if(bestKnownGPSLocation!=null){
                 publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownGPSLocation));
                 return;
             }
             if(bestKnownNetworkLocation!=null){
                 publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownNetworkLocation));
                 return;
             }
             AppLog.logWarningMsg("Bad luck-NO BEST LOCATION AVAILABLE");
             publishBestKnownLocation(null);
        }
    }


    private GPSData extractAllGeoInfFromLocation(Location location){
        bestKnownLocation = new GPSData();
        bestKnownLocation.setLatitude(location.getLatitude());  
        bestKnownLocation.setLongitude(location.getLongitude());    
        bestKnownLocation.setTimeStamp(location.getTime());
        bestKnownLocation.setSpeed(location.getSpeed()*3.8);
        bestKnownLocation.setNumberOfSatellites(numberOfSatellites);
        return bestKnownLocation;
    }

}


There is only one instance of service. As per the document

Multiple calls to Context.startService() do result in multiple corresponding calls to onStartCommand()), But only one service instance can exist.

On startService(), the Android system calls the service's onStartCommand() method. If the service is not already running, the system first calls onCreate(), then calls onStartCommand().


The only thing that can create this kind of scenario is that you have some kind of memory leak. Your service did it's work and stopped but didn't garbage collected. it probably happen few times and that is why you see many instances of it.

It's hard to find memory leaks but i would suggest you to start from the listeners. check if you unregistered them at the right time.

This link can help you to detect the leak: https://developer.android.com/studio/profile/am-memory.html

链接地址: http://www.djcxy.com/p/50650.html

上一篇: 在删除的包中删除

下一篇: 如何解决服务实例问题?