forked from upstream-mirrors/OpenTracks
Fix a memory leak that was observed each time a recording session was stopped.
This commit is contained in:
@@ -710,7 +710,6 @@ public class TrackRecordingService extends Service implements LocationListener {
|
|||||||
showNotification();
|
showNotification();
|
||||||
prefManager.shutdown();
|
prefManager.shutdown();
|
||||||
prefManager = null;
|
prefManager = null;
|
||||||
binder = null;
|
|
||||||
checkLocationListener.cancel();
|
checkLocationListener.cancel();
|
||||||
checkLocationListener = null;
|
checkLocationListener = null;
|
||||||
timer.cancel();
|
timer.cancel();
|
||||||
@@ -721,6 +720,15 @@ public class TrackRecordingService extends Service implements LocationListener {
|
|||||||
signalManager = null;
|
signalManager = null;
|
||||||
splitManager.shutdown();
|
splitManager.shutdown();
|
||||||
splitManager = null;
|
splitManager = null;
|
||||||
|
|
||||||
|
// Make sure we have no indirect references to this service.
|
||||||
|
locationManager = null;
|
||||||
|
notificationManager = null;
|
||||||
|
providerUtils = null;
|
||||||
|
binder.detachFromService();
|
||||||
|
binder = null;
|
||||||
|
|
||||||
|
// This should be the last operation.
|
||||||
releaseWakeLock();
|
releaseWakeLock();
|
||||||
|
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
@@ -896,75 +904,98 @@ public class TrackRecordingService extends Service implements LocationListener {
|
|||||||
updateCurrentWaypoint();
|
updateCurrentWaypoint();
|
||||||
return Long.parseLong(uri.getLastPathSegment());
|
return Long.parseLong(uri.getLastPathSegment());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ServiceBinder binder = new ServiceBinder(this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ITrackRecordingService is defined through IDL.
|
* TODO: There is a bug in Android that leaks Binder instances. This bug is
|
||||||
|
* especially visible if we have a non-static class, as there is no way to
|
||||||
|
* nullify reference to the outer class (the service).
|
||||||
|
* A workaround is to use a static class and explicitly clear service
|
||||||
|
* and detach it from the underlying Binder. With this approach, we minimize
|
||||||
|
* the leak to 24 bytes per each service instance.
|
||||||
|
*
|
||||||
|
* For more details, see the following bug:
|
||||||
|
* http://code.google.com/p/android/issues/detail?id=6426.
|
||||||
*/
|
*/
|
||||||
private ITrackRecordingService.Stub binder =
|
private static class ServiceBinder extends ITrackRecordingService.Stub {
|
||||||
new ITrackRecordingService.Stub() {
|
private TrackRecordingService service;
|
||||||
@Override
|
|
||||||
public boolean isRecording() {
|
public ServiceBinder(TrackRecordingService service) {
|
||||||
return TrackRecordingService.this.isRecording();
|
this.service = service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the reference to the outer class to minimize the leak.
|
||||||
|
*/
|
||||||
|
public void detachFromService() {
|
||||||
|
this.service = null;
|
||||||
|
attachInterface(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRecording() {
|
||||||
|
return service.isRecording();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getRecordingTrackId() {
|
public long getRecordingTrackId() {
|
||||||
return recordingTrackId;
|
return service.recordingTrackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasRecorded() {
|
public boolean hasRecorded() {
|
||||||
return providerUtils.getLastTrackId() >= 0;
|
return service.providerUtils.getLastTrackId() >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long startNewTrack() {
|
public long startNewTrack() {
|
||||||
return TrackRecordingService.this.startNewTrack();
|
return service.startNewTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert the given waypoint marker. Users can insert waypoint markers
|
* Insert the given waypoint marker. Users can insert waypoint markers
|
||||||
* to tag locations with a name, description, category etc.
|
* to tag locations with a name, description, category etc.
|
||||||
*
|
*
|
||||||
* @param waypoint a waypoint
|
* @param waypoint a waypoint
|
||||||
* @return the unique id of the inserted marker
|
* @return the unique id of the inserted marker
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public long insertWaypointMarker(Waypoint waypoint) {
|
public long insertWaypointMarker(Waypoint waypoint) {
|
||||||
return TrackRecordingService.this.insertWaypointMarker(waypoint);
|
return service.insertWaypointMarker(waypoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a statistics marker. A statistics marker holds the stats for
|
* Insert a statistics marker. A statistics marker holds the stats for
|
||||||
* the last segment up to this marker.
|
* the last segment up to this marker.
|
||||||
*
|
*
|
||||||
* @param location the location where to insert
|
* @param location the location where to insert
|
||||||
* @return the unique id of the inserted marker
|
* @return the unique id of the inserted marker
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public long insertStatisticsMarker(Location location) {
|
public long insertStatisticsMarker(Location location) {
|
||||||
return TrackRecordingService.this.insertStatisticsMarker(location);
|
return service.insertStatisticsMarker(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endCurrentTrack() {
|
public void endCurrentTrack() {
|
||||||
TrackRecordingService.this.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteAllTracks() {
|
public void deleteAllTracks() {
|
||||||
if (isRecording()) {
|
if (isRecording()) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Cannot delete all tracks while recording!");
|
"Cannot delete all tracks while recording!");
|
||||||
}
|
}
|
||||||
providerUtils.deleteAllTracks();
|
service.providerUtils.deleteAllTracks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void recordLocation(Location loc) {
|
public void recordLocation(Location loc) {
|
||||||
onLocationChanged(loc);
|
service.onLocationChanged(loc);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
public long startNewTrack() {
|
public long startNewTrack() {
|
||||||
Log.d(MyTracksConstants.TAG, "TrackRecordingService.startNewTrack");
|
Log.d(MyTracksConstants.TAG, "TrackRecordingService.startNewTrack");
|
||||||
|
|||||||
Reference in New Issue
Block a user