2014-01-29 5 views
1

내 서버에 GPS 데이터를 보내는 20 초마다 Alarm Manager를 기반으로 서비스를 시작합니다. 문제는 내 힙이며 할당 된 힙 크기는 계속 증가합니다. 힙 덤프를 분석 할 때 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; 
    } 

}

+0

는 당신이 우리에게 당신이 문제가 생각하는 코드를 공유 할 수 있습니다

이 링크는 누출을 감지하는 데 도움이 될 수 있습니다? –

+0

안녕하세요, 제 코드를 살펴 보시겠습니까? –

+0

메모리 누수 문제가 있습니다. 가비지 컬렉터는'Service' 인스턴스를 다시 사용할 수 없습니다. 당신은'addGpsStatusListener()'와'requestLocationUpdates()'를 호출하고 아마도'Service'가 멈춘 코드 경로가 있지만이 리스너들을 제거하지 않았습니다. 사랑 객체에 대한 힙 덤프를 검사하거나'Service.onDestroy()'에서 모든 청취자 등록을 해제 할 수 있습니다. –

답변

1

있습니다. Context.startService에 document

여러 통화에 따라() onStartCommand()), 여러 해당 호출이 발생할 않지만 하나의 서비스 인스턴스가 존재할 수 있습니다.

startService()에서 Android 시스템은 서비스의 onStartCommand() 메소드를 호출합니다. 서비스가 아직 실행되고 있지 않으면 시스템은 먼저 onCreate()를 호출 한 다음 onStartCommand()를 호출합니다.

+0

왜? 서비스가 실행 중이면 이전 서비스를 다시 사용하는 대신 인스턴스화해서는 안되기 때문입니다. –

+0

@bikash_binay 수정 된 답변 확인 –

0

이런 종류의 시나리오를 만들 수있는 유일한 방법은 사용자가 메모리 누출을 방지하는 것입니다. 서비스가 작동하고 중지되었지만 가비지 수집되지 않았습니다. 그것은 아마 몇 번 발생하고 그 이유는 당신이 그것의 많은 인스턴스를 볼 수 있습니다.

메모리 누수를 찾기는 어렵지만 청취자부터 시작하는 것이 좋습니다. 적시에 등록을 취소했는지 확인하십시오. https://developer.android.com/studio/profile/am-memory.html

관련 문제