forked from upstream-mirrors/OpenTracks
TrackPointIterator: removed manual batching as it should not be necessary.
This commit is contained in:
+15
-22
@@ -94,29 +94,22 @@ public class CustomContentProviderUtilsTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationIterator_noPoints() {
|
public void testLocationIterator_noPoints() {
|
||||||
testIterator(new Track.Id(1), 0, 1);
|
testIterator(new Track.Id(1), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationIterator_noBatchAscending() {
|
public void testLocationIterator_noAscending() {
|
||||||
testIterator(new Track.Id(1), 50, 100);
|
testIterator(new Track.Id(1), 50);
|
||||||
testIterator(new Track.Id(2), 50, 50);
|
testIterator(new Track.Id(2), 50);
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLocationIterator_batchAscending() {
|
|
||||||
testIterator(new Track.Id(1), 50, 11);
|
|
||||||
testIterator(new Track.Id(2), 50, 25);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationIterator_largeTrack() {
|
public void testLocationIterator_largeTrack() {
|
||||||
testIterator(new Track.Id(1), 20000, 2000);
|
testIterator(new Track.Id(1), 20000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testIterator(Track.Id trackId, int numPoints, int batchSize) {
|
private void testIterator(Track.Id trackId, int numPoints) {
|
||||||
long lastPointId = initializeTrack(trackId, numPoints);
|
TrackPoint.Id lastPointId = initializeTrack(trackId, numPoints);
|
||||||
contentProviderUtils.setDefaultCursorBatchSize(batchSize);
|
|
||||||
List<TrackPoint> locations = new ArrayList<>(numPoints);
|
List<TrackPoint> locations = new ArrayList<>(numPoints);
|
||||||
try (TrackPointIterator it = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
|
try (TrackPointIterator it = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
@@ -124,13 +117,13 @@ public class CustomContentProviderUtilsTest {
|
|||||||
assertNotNull(trackPoint);
|
assertNotNull(trackPoint);
|
||||||
locations.add(trackPoint);
|
locations.add(trackPoint);
|
||||||
// Make sure the IDs are returned in the right order.
|
// Make sure the IDs are returned in the right order.
|
||||||
assertEquals(lastPointId - numPoints + locations.size(), trackPoint.getId().getId());
|
assertEquals(lastPointId.getId() - numPoints + locations.size(), trackPoint.getId().getId());
|
||||||
}
|
}
|
||||||
assertEquals(numPoints, locations.size());
|
assertEquals(numPoints, locations.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long initializeTrack(Track.Id id, int numPoints) {
|
private TrackPoint.Id initializeTrack(Track.Id id, int numPoints) {
|
||||||
Track track = new Track();
|
Track track = new Track();
|
||||||
track.setId(id);
|
track.setId(id);
|
||||||
track.setName("Test: " + id.getId());
|
track.setName("Test: " + id.getId());
|
||||||
@@ -150,17 +143,17 @@ public class CustomContentProviderUtilsTest {
|
|||||||
contentProviderUtils.bulkInsertTrackPoint(trackPoints, id);
|
contentProviderUtils.bulkInsertTrackPoint(trackPoints, id);
|
||||||
|
|
||||||
// Load all inserted trackPoints.
|
// Load all inserted trackPoints.
|
||||||
long lastPointId = -1;
|
TrackPoint.Id lastPointId = null;
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
try (TrackPointIterator it = contentProviderUtils.getTrackPointLocationIterator(id, null)) {
|
try (TrackPointIterator it = contentProviderUtils.getTrackPointLocationIterator(id, null)) {
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
TrackPoint trackPoint = it.next();
|
TrackPoint trackPoint = it.next();
|
||||||
lastPointId = trackPoint.getId().getId();
|
lastPointId = trackPoint.getId();
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(numPoints == 0 || lastPointId > 0);
|
assertTrue(numPoints == 0 || lastPointId.getId() > 0);
|
||||||
assertEquals(numPoints, counter);
|
assertEquals(numPoints, counter);
|
||||||
|
|
||||||
return lastPointId;
|
return lastPointId;
|
||||||
@@ -770,9 +763,9 @@ public class CustomContentProviderUtilsTest {
|
|||||||
|
|
||||||
// when / then
|
// when / then
|
||||||
contentProviderUtils.bulkInsertTrackPoint(track.second, trackId);
|
contentProviderUtils.bulkInsertTrackPoint(track.second, trackId);
|
||||||
assertEquals(20, contentProviderUtils.getTrackPointCursor(trackId, null, 1000).getCount());
|
assertEquals(20, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
|
||||||
contentProviderUtils.bulkInsertTrackPoint(track.second.subList(0, 8), trackId);
|
contentProviderUtils.bulkInsertTrackPoint(track.second.subList(0, 8), trackId);
|
||||||
assertEquals(28, contentProviderUtils.getTrackPointCursor(trackId, null, 1000).getCount());
|
assertEquals(28, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -879,7 +872,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
.map(TrackPoint.Id::new).collect(Collectors.toList());
|
.map(TrackPoint.Id::new).collect(Collectors.toList());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, trackpointIds.get(8), 5);
|
Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, trackpointIds.get(8));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(2, cursor.getCount());
|
assertEquals(2, cursor.getCount());
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ public class ContentProviderUtils {
|
|||||||
private static final String ID_SEPARATOR = ",";
|
private static final String ID_SEPARATOR = ",";
|
||||||
|
|
||||||
private final ContentResolver contentResolver;
|
private final ContentResolver contentResolver;
|
||||||
private int defaultCursorBatchSize = 2000;
|
|
||||||
|
|
||||||
public ContentProviderUtils(Context context) {
|
public ContentProviderUtils(Context context) {
|
||||||
contentResolver = context.getContentResolver();
|
contentResolver = context.getContentResolver();
|
||||||
@@ -176,7 +175,7 @@ public class ContentProviderUtils {
|
|||||||
|
|
||||||
// Delete track last since it triggers a database vacuum call
|
// Delete track last since it triggers a database vacuum call
|
||||||
String whereClause = String.format(TracksColumns._ID + " IN (%s)", TextUtils.join(",", Collections.nCopies(trackIds.size(), "?")));
|
String whereClause = String.format(TracksColumns._ID + " IN (%s)", TextUtils.join(",", Collections.nCopies(trackIds.size(), "?")));
|
||||||
contentResolver.delete(TracksColumns.CONTENT_URI, whereClause, trackIds.stream().map(id->Long.toString(id.getId())).toArray(String[]::new));
|
contentResolver.delete(TracksColumns.CONTENT_URI, whereClause, trackIds.stream().map(id -> Long.toString(id.getId())).toArray(String[]::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteTrack(Context context, @NonNull Track.Id trackId) {
|
public void deleteTrack(Context context, @NonNull Track.Id trackId) {
|
||||||
@@ -632,9 +631,9 @@ public class ContentProviderUtils {
|
|||||||
*
|
*
|
||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
* @param startTrackPointId the starting trackPoint id. `null` to ignore
|
* @param startTrackPointId the starting trackPoint id. `null` to ignore
|
||||||
* @param maxLocations maximum number of locations to return. `null` for no limit
|
|
||||||
*/
|
*/
|
||||||
public Cursor getTrackPointCursor(Track.Id trackId, TrackPoint.Id startTrackPointId, Integer maxLocations) {
|
@NonNull
|
||||||
|
public Cursor getTrackPointCursor(@NonNull Track.Id trackId, TrackPoint.Id startTrackPointId) {
|
||||||
String selection;
|
String selection;
|
||||||
String[] selectionArgs;
|
String[] selectionArgs;
|
||||||
if (startTrackPointId != null) {
|
if (startTrackPointId != null) {
|
||||||
@@ -645,11 +644,7 @@ public class ContentProviderUtils {
|
|||||||
selectionArgs = new String[]{Long.toString(trackId.getId())};
|
selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||||
}
|
}
|
||||||
|
|
||||||
String sortOrder = TrackPointsColumns.DEFAULT_SORT_ORDER;
|
return getTrackPointCursor(null, selection, selectionArgs, TrackPointsColumns.DEFAULT_SORT_ORDER);
|
||||||
if (maxLocations != null) {
|
|
||||||
sortOrder += " LIMIT " + maxLocations;
|
|
||||||
}
|
|
||||||
return getTrackPointCursor(null, selection, selectionArgs, sortOrder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -763,39 +758,23 @@ public class ContentProviderUtils {
|
|||||||
return contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, projection, selection, selectionArgs, sortOrder);
|
return contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, projection, selection, selectionArgs, sortOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated //Use TrackPointIterator instead
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public List<TrackPoint> getTrackPoints(Track.Id trackId) {
|
public List<TrackPoint> getTrackPoints(Track.Id trackId) {
|
||||||
List<TrackPoint> trackPoints = null;
|
List<TrackPoint> trackPoints;
|
||||||
|
|
||||||
try (Cursor trackPointCursor = getTrackPointCursor(trackId, null, null)) {
|
try (Cursor trackPointCursor = getTrackPointCursor(trackId, null)) {
|
||||||
if (trackPointCursor != null) {
|
trackPointCursor.moveToFirst();
|
||||||
trackPointCursor.moveToFirst();
|
trackPoints = new ArrayList<>(trackPointCursor.getCount());
|
||||||
trackPoints = new ArrayList<>(trackPointCursor.getCount());
|
for (int i = 0; i < trackPointCursor.getCount(); i++) {
|
||||||
for (int i = 0; i < trackPointCursor.getCount(); i++) {
|
trackPoints.add(createTrackPoint(trackPointCursor));
|
||||||
trackPoints.add(createTrackPoint(trackPointCursor));
|
trackPointCursor.moveToNext();
|
||||||
trackPointCursor.moveToNext();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return trackPoints;
|
return trackPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getDefaultCursorBatchSize() {
|
|
||||||
return defaultCursorBatchSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the default cursor batch size. For testing purpose.
|
|
||||||
*
|
|
||||||
* @param defaultCursorBatchSize the default cursor batch size
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
void setDefaultCursorBatchSize(int defaultCursorBatchSize) {
|
|
||||||
this.defaultCursorBatchSize = defaultCursorBatchSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static String formatIdListForUri(Track.Id... trackIds) {
|
public static String formatIdListForUri(Track.Id... trackIds) {
|
||||||
long[] ids = new long[trackIds.length];
|
long[] ids = new long[trackIds.length];
|
||||||
for (int i = 0; i < trackIds.length; i++) {
|
for (int i = 0; i < trackIds.length; i++) {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
package de.dennisguse.opentracks.content.provider;
|
package de.dennisguse.opentracks.content.provider;
|
||||||
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.util.Log;
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
@@ -10,9 +11,8 @@ import de.dennisguse.opentracks.content.data.Track;
|
|||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A lightweight wrapper around the original {@link Cursor} with a method to clean up.
|
* A lightweight wrapper around the original {@link Cursor}.
|
||||||
*/
|
*/
|
||||||
//TODO Remove batching; that should be handled by the database/contentprovider (i.e., already in place as we use a cursor)!
|
|
||||||
public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
|
public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
|
||||||
|
|
||||||
private static final String TAG = TrackPointIterator.class.getSimpleName();
|
private static final String TAG = TrackPointIterator.class.getSimpleName();
|
||||||
@@ -20,7 +20,6 @@ public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
|
|||||||
private final ContentProviderUtils contentProviderUtils;
|
private final ContentProviderUtils contentProviderUtils;
|
||||||
private final Track.Id trackId;
|
private final Track.Id trackId;
|
||||||
private final CachedTrackPointsIndexes indexes;
|
private final CachedTrackPointsIndexes indexes;
|
||||||
private TrackPoint.Id lastTrackPointId = null;
|
|
||||||
private Cursor cursor;
|
private Cursor cursor;
|
||||||
|
|
||||||
public TrackPointIterator(ContentProviderUtils contentProviderUtils, Track.Id trackId, TrackPoint.Id startTrackPointId) {
|
public TrackPointIterator(ContentProviderUtils contentProviderUtils, Track.Id trackId, TrackPoint.Id startTrackPointId) {
|
||||||
@@ -28,28 +27,11 @@ public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
|
|||||||
this.trackId = trackId;
|
this.trackId = trackId;
|
||||||
|
|
||||||
cursor = getCursor(startTrackPointId);
|
cursor = getCursor(startTrackPointId);
|
||||||
indexes = cursor != null ? new CachedTrackPointsIndexes(cursor)
|
indexes = new CachedTrackPointsIndexes(cursor);
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the track point cursor.
|
|
||||||
*
|
|
||||||
* @param trackPointId the starting track point id
|
|
||||||
*/
|
|
||||||
private Cursor getCursor(TrackPoint.Id trackPointId) {
|
private Cursor getCursor(TrackPoint.Id trackPointId) {
|
||||||
return contentProviderUtils.getTrackPointCursor(trackId, trackPointId, contentProviderUtils.getDefaultCursorBatchSize());
|
return contentProviderUtils.getTrackPointCursor(trackId, trackPointId);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Advances the cursor to the next batch. Returns true if successful.
|
|
||||||
*/
|
|
||||||
private boolean advanceCursorToNextBatch() {
|
|
||||||
TrackPoint.Id trackPointId = lastTrackPointId == null ? null : new TrackPoint.Id(lastTrackPointId.getId() + 1);
|
|
||||||
Log.d(TAG, "Advancing track point id: " + trackPointId);
|
|
||||||
cursor.close();
|
|
||||||
cursor = getCursor(trackPointId);
|
|
||||||
return cursor != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -57,29 +39,15 @@ public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
|
|||||||
if (cursor == null) {
|
if (cursor == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (cursor.isAfterLast()) {
|
return !cursor.isLast() && !cursor.isAfterLast();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (cursor.isLast()) {
|
|
||||||
if (cursor.getCount() != contentProviderUtils.getDefaultCursorBatchSize()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return advanceCursorToNextBatch() && !cursor.isAfterLast();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@NonNull
|
||||||
public TrackPoint next() {
|
public TrackPoint next() {
|
||||||
if (cursor == null) {
|
if (cursor == null || !cursor.moveToNext()) {
|
||||||
throw new NoSuchElementException();
|
throw new NoSuchElementException();
|
||||||
}
|
}
|
||||||
if (!cursor.moveToNext()) {
|
|
||||||
if (!advanceCursorToNextBatch() || !cursor.moveToNext()) {
|
|
||||||
throw new NoSuchElementException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastTrackPointId = new TrackPoint.Id(cursor.getLong(indexes.idIndex));
|
|
||||||
return ContentProviderUtils.fillTrackPoint(cursor, indexes);
|
return ContentProviderUtils.fillTrackPoint(cursor, indexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -172,6 +172,7 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
|
|||||||
Track track = contentProviderUtils.getTrack(PreferencesUtils.getRecordingTrackId(sharedPreferences, context));
|
Track track = contentProviderUtils.getTrack(PreferencesUtils.getRecordingTrackId(sharedPreferences, context));
|
||||||
String category = track != null ? track.getCategory() : "";
|
String category = track != null ? track.getCategory() : "";
|
||||||
|
|
||||||
|
//TODO Querying all TrackPoints all the time is inefficient; use TrackDataHub
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(track.getId());
|
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(track.getId());
|
||||||
boolean isMetricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, context);
|
boolean isMetricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, context);
|
||||||
boolean isReportSpeed = PreferencesUtils.isReportSpeed(sharedPreferences, context, category);
|
boolean isReportSpeed = PreferencesUtils.isReportSpeed(sharedPreferences, context, category);
|
||||||
|
|||||||
Reference in New Issue
Block a user