如何解决服务实例问题?

我正在每20秒钟启动一次基于Alarm Manager的服务,它将GPS数据发送到我的服务器。 问题是我的堆和分配的堆大小不断增加。 当我分析堆转储时,我发现服务实例的数量等于startService()的调用次数。 如何避免这个问题?


    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;
    }

}


只有一个服务实例。 根据该文件

多次调用Context.startService()会导致对onStartCommand()的多次相应调用,但只能存在一个服务实例。

在startService()上,Android系统调用服务的onStartCommand()方法。 如果服务尚未运行,则系统首先调用onCreate(),然后调用onStartCommand()。


唯一可以创建这种场景的是你有一些内存泄漏。 你的服务做到了,停止了,但没有收集垃圾。 它可能发生几次,这就是为什么你看到它的很多例子。

很难找到内存泄漏,但我建议你从听众开始。 检查你是否在正确的时间注销它们。

这个链接可以帮助你检测泄漏:https://developer.android.com/studio/profile/am-memory.html

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

上一篇: How to fix Service Instance Issue?

下一篇: Android widget onReceive crashing