forked from upstream-mirrors/OpenTracks
Fixing incremental loading when there's only a single listener.
This commit is contained in:
@@ -21,6 +21,7 @@ import static com.google.android.apps.mytracks.Constants.TAG;
|
|||||||
|
|
||||||
import com.google.android.apps.mytracks.Constants;
|
import com.google.android.apps.mytracks.Constants;
|
||||||
import com.google.android.apps.mytracks.content.DataSourceManager.DataSourceListener;
|
import com.google.android.apps.mytracks.content.DataSourceManager.DataSourceListener;
|
||||||
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.DoubleBufferedLocationFactory;
|
||||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
|
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.LocationIterator;
|
||||||
import com.google.android.apps.mytracks.content.TrackDataListener.ProviderState;
|
import com.google.android.apps.mytracks.content.TrackDataListener.ProviderState;
|
||||||
import com.google.android.apps.mytracks.content.TrackDataListeners.ListenerRegistration;
|
import com.google.android.apps.mytracks.content.TrackDataListeners.ListenerRegistration;
|
||||||
@@ -47,7 +48,10 @@ import java.util.Set;
|
|||||||
* Track data hub, which receives data (both live and recorded) from many
|
* Track data hub, which receives data (both live and recorded) from many
|
||||||
* different sources and distributes it to those interested after some standard
|
* different sources and distributes it to those interested after some standard
|
||||||
* processing.
|
* processing.
|
||||||
*
|
*
|
||||||
|
* TODO: Simplify the threading model here, it's overly complex and it's not obvious why
|
||||||
|
* certain race conditions won't happen.
|
||||||
|
*
|
||||||
* @author Rodrigo Damazio
|
* @author Rodrigo Damazio
|
||||||
*/
|
*/
|
||||||
public class TrackDataHub {
|
public class TrackDataHub {
|
||||||
@@ -181,6 +185,7 @@ public class TrackDataHub {
|
|||||||
private long lastSeenLocationId;
|
private long lastSeenLocationId;
|
||||||
private int numLoadedPoints;
|
private int numLoadedPoints;
|
||||||
private int lastSamplingFrequency;
|
private int lastSamplingFrequency;
|
||||||
|
private DoubleBufferedLocationFactory locationFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor.
|
* Default constructor.
|
||||||
@@ -203,6 +208,7 @@ public class TrackDataHub {
|
|||||||
this.providerUtils = providerUtils;
|
this.providerUtils = providerUtils;
|
||||||
this.dataSources = dataSources;
|
this.dataSources = dataSources;
|
||||||
this.dataSourceManager = new DataSourceManager(dataSourceListener, dataSources);
|
this.dataSourceManager = new DataSourceManager(dataSourceListener, dataSources);
|
||||||
|
this.locationFactory = new DoubleBufferedLocationFactory();
|
||||||
|
|
||||||
SELECTED_TRACK_KEY = context.getString(R.string.selected_track_key);
|
SELECTED_TRACK_KEY = context.getString(R.string.selected_track_key);
|
||||||
RECORDING_TRACK_KEY = context.getString(R.string.recording_track_key);
|
RECORDING_TRACK_KEY = context.getString(R.string.recording_track_key);
|
||||||
@@ -369,11 +375,20 @@ public class TrackDataHub {
|
|||||||
selectedTrackId = trackId;
|
selectedTrackId = trackId;
|
||||||
|
|
||||||
// Force it to reload data from the beginning.
|
// Force it to reload data from the beginning.
|
||||||
|
Log.d(TAG, "Loading track");
|
||||||
|
resetState();
|
||||||
|
|
||||||
|
loadDataForAllListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the internal state of what data has already been loaded into listeners.
|
||||||
|
*/
|
||||||
|
private void resetState() {
|
||||||
firstSeenLocationId = -1;
|
firstSeenLocationId = -1;
|
||||||
lastSeenLocationId = -1;
|
lastSeenLocationId = -1;
|
||||||
numLoadedPoints = 0;
|
numLoadedPoints = 0;
|
||||||
|
lastSamplingFrequency = -1;
|
||||||
loadDataForAllListeners();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -401,6 +416,13 @@ public class TrackDataHub {
|
|||||||
public void unregisterTrackDataListener(TrackDataListener listener) {
|
public void unregisterTrackDataListener(TrackDataListener listener) {
|
||||||
synchronized (listeners) {
|
synchronized (listeners) {
|
||||||
listeners.unregisterTrackDataListener(listener);
|
listeners.unregisterTrackDataListener(listener);
|
||||||
|
|
||||||
|
if (!listeners.hasListeners()) {
|
||||||
|
// We lost our last listener, don't bother keeping the listener state.
|
||||||
|
// If any of the old listeners happens to be re-added, we'll use state from its
|
||||||
|
// old registration instead.
|
||||||
|
resetState();
|
||||||
|
}
|
||||||
|
|
||||||
// Don't load any data or start internal listeners if start() hasn't been
|
// Don't load any data or start internal listeners if start() hasn't been
|
||||||
// called. When it is called, we'll do both things.
|
// called. When it is called, we'll do both things.
|
||||||
@@ -417,12 +439,14 @@ public class TrackDataHub {
|
|||||||
ListenerRegistration registration;
|
ListenerRegistration registration;
|
||||||
synchronized (listeners) {
|
synchronized (listeners) {
|
||||||
registration = listeners.getRegistration(listener);
|
registration = listeners.getRegistration(listener);
|
||||||
|
reloadDataForListener(registration);
|
||||||
}
|
}
|
||||||
reloadDataForListener(registration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reloads all track data received so far into the specified listeners.
|
* Reloads all track data received so far into the specified listeners.
|
||||||
|
*
|
||||||
|
* Assumes it's called from a block that synchronizes on {@link #listeners}.
|
||||||
*/
|
*/
|
||||||
private void reloadDataForListener(final ListenerRegistration registration) {
|
private void reloadDataForListener(final ListenerRegistration registration) {
|
||||||
if (!started) {
|
if (!started) {
|
||||||
@@ -433,6 +457,11 @@ public class TrackDataHub {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If a listener happens to be added after this method but before the Runnable below is
|
||||||
|
// executed, it will have triggered a separate call to load data only up to the point this
|
||||||
|
// listener got to. This is ensured by being synchronized on listeners.
|
||||||
|
final boolean isOnlyListener = (listeners.getNumListeners() == 1);
|
||||||
|
|
||||||
runInListenerThread(new Runnable() {
|
runInListenerThread(new Runnable() {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
@@ -466,6 +495,7 @@ public class TrackDataHub {
|
|||||||
if (interestedInPoints || interestedInSampledOutPoints) {
|
if (interestedInPoints || interestedInSampledOutPoints) {
|
||||||
long minPointId = 0;
|
long minPointId = 0;
|
||||||
int previousNumPoints = 0;
|
int previousNumPoints = 0;
|
||||||
|
|
||||||
if (reloadAll) {
|
if (reloadAll) {
|
||||||
// Clear existing points and send them all again
|
// Clear existing points and send them all again
|
||||||
notifyPointsCleared(listenerSet);
|
notifyPointsCleared(listenerSet);
|
||||||
@@ -475,7 +505,9 @@ public class TrackDataHub {
|
|||||||
previousNumPoints = registration.numLoadedPoints;
|
previousNumPoints = registration.numLoadedPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyPointsUpdated(false,
|
// If this is the only listener we have registered, keep the state that we serve to it as
|
||||||
|
// a reference for other future listeners.
|
||||||
|
notifyPointsUpdated(isOnlyListener,
|
||||||
minPointId,
|
minPointId,
|
||||||
previousNumPoints,
|
previousNumPoints,
|
||||||
listenerSet,
|
listenerSet,
|
||||||
@@ -877,7 +909,7 @@ public class TrackDataHub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronous version of the above method.
|
* Synchronous version of the above method.
|
||||||
*/
|
*/
|
||||||
private void notifyPointsUpdatedSync(boolean keepState,
|
private void notifyPointsUpdatedSync(boolean keepState,
|
||||||
long minPointId, int previousNumPoints,
|
long minPointId, int previousNumPoints,
|
||||||
@@ -929,9 +961,6 @@ public class TrackDataHub {
|
|||||||
long lastStoredLocationId = providerUtils.getLastLocationId(currentSelectedTrackId);
|
long lastStoredLocationId = providerUtils.getLastLocationId(currentSelectedTrackId);
|
||||||
int pointSamplingFrequency = -1;
|
int pointSamplingFrequency = -1;
|
||||||
|
|
||||||
// Create a double-buffering location provider.
|
|
||||||
MyTracksProviderUtils.DoubleBufferedLocationFactory locationFactory =
|
|
||||||
new MyTracksProviderUtils.DoubleBufferedLocationFactory();
|
|
||||||
LocationIterator it = providerUtils.getLocationIterator(
|
LocationIterator it = providerUtils.getLocationIterator(
|
||||||
currentSelectedTrackId, minPointId, false, locationFactory);
|
currentSelectedTrackId, minPointId, false, locationFactory);
|
||||||
|
|
||||||
|
|||||||
@@ -163,4 +163,8 @@ class TrackDataListeners {
|
|||||||
public boolean hasListeners() {
|
public boolean hasListeners() {
|
||||||
return !registeredListeners.isEmpty();
|
return !registeredListeners.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getNumListeners() {
|
||||||
|
return registeredListeners.size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user