From e4b5fb28b996383736fed065b94348645bde8d3d Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Thu, 29 May 2014 12:39:18 +0200 Subject: Add more parallelism in static maps downloads --- main/src/cgeo/geocaching/CacheDetailActivity.java | 3 +- main/src/cgeo/geocaching/EditWaypointActivity.java | 2 +- main/src/cgeo/geocaching/Geocache.java | 5 +- main/src/cgeo/geocaching/StaticMapsActivity.java | 5 +- main/src/cgeo/geocaching/StaticMapsProvider.java | 154 ++++++++++----------- main/src/cgeo/geocaching/files/GPXImporter.java | 3 +- main/src/cgeo/geocaching/network/HtmlImage.java | 6 +- main/src/cgeo/geocaching/utils/RxUtils.java | 11 ++ 8 files changed, 101 insertions(+), 88 deletions(-) (limited to 'main') diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index 815d43b..7ada90a 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -46,6 +46,7 @@ import cgeo.geocaching.utils.CryptUtils; import cgeo.geocaching.utils.ImageUtils; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.MatcherWrapper; +import cgeo.geocaching.utils.RxUtils; import cgeo.geocaching.utils.SimpleCancellableHandler; import cgeo.geocaching.utils.SimpleHandler; import cgeo.geocaching.utils.TextUtils; @@ -1341,7 +1342,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity downloadDifferentZooms(final String geocode, final String markerUrl, final String prefix, final String latlonMap, final int edge, final Parameters waypoints) { + return Observable.merge(downloadMap(geocode, 20, SATELLITE, markerUrl, prefix + '1', "", latlonMap, edge, edge, waypoints), + downloadMap(geocode, 18, SATELLITE, markerUrl, prefix + '2', "", latlonMap, edge, edge, waypoints), + downloadMap(geocode, 16, ROADMAP, markerUrl, prefix + '3', "", latlonMap, edge, edge, waypoints), + downloadMap(geocode, 14, ROADMAP, markerUrl, prefix + '4', "", latlonMap, edge, edge, waypoints), + downloadMap(geocode, 11, ROADMAP, markerUrl, prefix + '5', "", latlonMap, edge, edge, waypoints)); } - private static void downloadMap(final String geocode, final int zoom, final String mapType, final String markerUrl, final String prefix, final String shadow, final String latlonMap, final int width, final int height, final Parameters waypoints) { - final Parameters params = new Parameters( - "center", latlonMap, - "zoom", String.valueOf(zoom), - "size", String.valueOf(limitSize(width)) + 'x' + String.valueOf(limitSize(height)), - "maptype", mapType, - "markers", "icon:" + markerUrl + '|' + shadow + latlonMap, - "sensor", "false"); - if (waypoints != null) { - params.addAll(waypoints); - } - final HttpResponse httpResponse = Network.getRequest(GOOGLE_STATICMAP_URL, params); + private static Observable downloadMap(final String geocode, final int zoom, final String mapType, final String markerUrl, final String prefix, final String shadow, final String latlonMap, final int width, final int height, final Parameters waypoints) { + return Async.fromAction(new Action0() { + @Override + public void call() { + final Parameters params = new Parameters( + "center", latlonMap, + "zoom", String.valueOf(zoom), + "size", String.valueOf(limitSize(width)) + 'x' + String.valueOf(limitSize(height)), + "maptype", mapType, + "markers", "icon:" + markerUrl + '|' + shadow + latlonMap, + "sensor", "false"); + if (waypoints != null) { + params.addAll(waypoints); + } + final HttpResponse httpResponse = Network.getRequest(GOOGLE_STATICMAP_URL, params); - if (httpResponse == null) { - Log.e("StaticMapsProvider.downloadMap: httpResponse is null"); - return; - } - if (httpResponse.getStatusLine().getStatusCode() != 200) { - Log.d("StaticMapsProvider.downloadMap: httpResponseCode = " + httpResponse.getStatusLine().getStatusCode()); - return; - } - final File file = getMapFile(geocode, prefix, true); - if (LocalStorage.saveEntityToFile(httpResponse, file)) { - // Delete image if it has no contents - final long fileSize = file.length(); - if (fileSize < MIN_MAP_IMAGE_BYTES) { - FileUtils.deleteIgnoringFailure(file); + if (httpResponse == null) { + Log.e("StaticMapsProvider.downloadMap: httpResponse is null"); + return; + } + if (httpResponse.getStatusLine().getStatusCode() != 200) { + Log.d("StaticMapsProvider.downloadMap: httpResponseCode = " + httpResponse.getStatusLine().getStatusCode()); + return; + } + final File file = getMapFile(geocode, prefix, true); + if (LocalStorage.saveEntityToFile(httpResponse, file)) { + // Delete image if it has no contents + final long fileSize = file.length(); + if (fileSize < MIN_MAP_IMAGE_BYTES) { + FileUtils.deleteIgnoringFailure(file); + } + } } - } + }, prefix, Schedulers.io()); } private static int limitSize(final int imageSize) { return Math.min(imageSize, GOOGLE_MAPS_MAX_SIZE); } - public static void downloadMaps(final Geocache cache) { + public static Observable downloadMaps(final Geocache cache) { if ((!Settings.isStoreOfflineMaps() && !Settings.isStoreOfflineWpMaps()) || StringUtils.isBlank(cache.getGeocode())) { - return; + return Observable.empty(); } int edge = guessMaxDisplaySide(); + final List> downloaders = new LinkedList>(); + if (Settings.isStoreOfflineMaps() && cache.getCoords() != null) { - storeCachePreviewMap(cache); - storeCacheStaticMap(cache, edge, false); + downloaders.add(storeCachePreviewMap(cache)); + downloaders.add(storeCacheStaticMap(cache, edge)); } // clean old and download static maps for waypoints if one is missing if (Settings.isStoreOfflineWpMaps()) { for (final Waypoint waypoint : cache.getWaypoints()) { if (!hasAllStaticMapsForWaypoint(cache.getGeocode(), waypoint)) { - refreshAllWpStaticMaps(cache, edge); + downloaders.add(refreshAllWpStaticMaps(cache, edge)); } } } + + return Observable.merge(downloaders); } /** @@ -124,44 +135,47 @@ public final class StaticMapsProvider { * @param edge * The boundings */ - private static void refreshAllWpStaticMaps(final Geocache cache, final int edge) { + private static Observable refreshAllWpStaticMaps(final Geocache cache, final int edge) { LocalStorage.deleteFilesWithPrefix(cache.getGeocode(), MAP_FILENAME_PREFIX + WAYPOINT_PREFIX); + final List> downloaders = new LinkedList>(); for (Waypoint waypoint : cache.getWaypoints()) { - storeWaypointStaticMap(cache.getGeocode(), edge, waypoint, false); + downloaders.add(storeWaypointStaticMap(cache.getGeocode(), edge, waypoint)); } + return Observable.merge(downloaders); } - public static void storeWaypointStaticMap(final Geocache cache, final Waypoint waypoint, final boolean waitForResult) { - int edge = StaticMapsProvider.guessMaxDisplaySide(); - storeWaypointStaticMap(cache.getGeocode(), edge, waypoint, waitForResult); + public static Observable storeWaypointStaticMap(final Geocache cache, final Waypoint waypoint) { + final int edge = StaticMapsProvider.guessMaxDisplaySide(); + return storeWaypointStaticMap(cache.getGeocode(), edge, waypoint); } - private static void storeWaypointStaticMap(final String geocode, final int edge, final Waypoint waypoint, final boolean waitForResult) { + private static Observable storeWaypointStaticMap(final String geocode, final int edge, final Waypoint waypoint) { if (geocode == null) { Log.e("storeWaypointStaticMap - missing input parameter geocode"); - return; + return Observable.empty(); } if (waypoint == null) { Log.e("storeWaypointStaticMap - missing input parameter waypoint"); - return; + return Observable.empty(); } if (waypoint.getCoords() == null) { - return; + return Observable.empty(); } String wpLatlonMap = waypoint.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA); String wpMarkerUrl = getWpMarkerUrl(waypoint); if (!hasAllStaticMapsForWaypoint(geocode, waypoint)) { // download map images in separate background thread for higher performance - downloadMaps(geocode, wpMarkerUrl, WAYPOINT_PREFIX + waypoint.getId() + '_' + waypoint.getStaticMapsHashcode() + "_", wpLatlonMap, edge, null, waitForResult); + return downloadMaps(geocode, wpMarkerUrl, WAYPOINT_PREFIX + waypoint.getId() + '_' + waypoint.getStaticMapsHashcode() + "_", wpLatlonMap, edge, null); } + return Observable.empty(); } - public static void storeCacheStaticMap(final Geocache cache, final boolean waitForResult) { + public static Observable storeCacheStaticMap(final Geocache cache) { int edge = guessMaxDisplaySide(); - storeCacheStaticMap(cache, edge, waitForResult); + return storeCacheStaticMap(cache, edge); } - private static void storeCacheStaticMap(final Geocache cache, final int edge, final boolean waitForResult) { + private static Observable storeCacheStaticMap(final Geocache cache, final int edge) { final String latlonMap = cache.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA); final Parameters waypoints = new Parameters(); for (final Waypoint waypoint : cache.getWaypoints()) { @@ -173,15 +187,15 @@ public final class StaticMapsProvider { } // download map images in separate background thread for higher performance final String cacheMarkerUrl = getCacheMarkerUrl(cache); - downloadMaps(cache.getGeocode(), cacheMarkerUrl, "", latlonMap, edge, waypoints, waitForResult); + return downloadMaps(cache.getGeocode(), cacheMarkerUrl, "", latlonMap, edge, waypoints); } - public static void storeCachePreviewMap(final Geocache cache) { + public static Observable storeCachePreviewMap(final Geocache cache) { final String latlonMap = cache.getCoords().format(Format.LAT_LON_DECDEGREE_COMMA); final Point displaySize = Compatibility.getDisplaySize(); final int minSize = Math.min(displaySize.x, displaySize.y); final String markerUrl = MARKERS_URL + "my_location_mdpi.png"; - downloadMap(cache.getGeocode(), 15, ROADMAP, markerUrl, PREFIX_PREVIEW, "shadow:false|", latlonMap, minSize, minSize, null); + return downloadMap(cache.getGeocode(), 15, ROADMAP, markerUrl, PREFIX_PREVIEW, "shadow:false|", latlonMap, minSize, minSize, null); } private static int guessMaxDisplaySide() { @@ -189,24 +203,10 @@ public final class StaticMapsProvider { return Math.max(displaySize.x, displaySize.y) - 25; } - private static void downloadMaps(final String geocode, final String markerUrl, final String prefix, final String latlonMap, final int edge, - final Parameters waypoints, final boolean waitForResult) { - if (waitForResult) { - downloadDifferentZooms(geocode, markerUrl, prefix, latlonMap, edge, waypoints); - } - else { - final Runnable currentTask = new Runnable() { - @Override - public void run() { - downloadDifferentZooms(geocode, markerUrl, prefix, latlonMap, edge, waypoints); - } - }; - try { - POOL.add(currentTask, 20, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Log.e("StaticMapsProvider.downloadMaps error adding task", e); - } - } + private static Observable downloadMaps(final String geocode, final String markerUrl, final String prefix, + final String latlonMap, final int edge, + final Parameters waypoints) { + return downloadDifferentZooms(geocode, markerUrl, prefix, latlonMap, edge, waypoints); } private static String getCacheMarkerUrl(final Geocache cache) { diff --git a/main/src/cgeo/geocaching/files/GPXImporter.java b/main/src/cgeo/geocaching/files/GPXImporter.java index f87e6b9..52f68e1 100644 --- a/main/src/cgeo/geocaching/files/GPXImporter.java +++ b/main/src/cgeo/geocaching/files/GPXImporter.java @@ -12,6 +12,7 @@ import cgeo.geocaching.settings.Settings; import cgeo.geocaching.ui.dialog.Dialogs; import cgeo.geocaching.utils.CancellableHandler; import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.RxUtils; import org.apache.commons.lang3.StringUtils; import org.eclipse.jdt.annotation.NonNull; @@ -226,7 +227,7 @@ public class GPXImporter { final Geocache cache = DataStore.loadCache(geocode, LoadFlags.LOAD_WAYPOINTS); if (cache != null) { Log.d("GPXImporter.ImportThread.importStaticMaps start downloadMaps for cache " + geocode); - StaticMapsProvider.downloadMaps(cache); + RxUtils.waitForCompletion(StaticMapsProvider.downloadMaps(cache)); } else { Log.d("GPXImporter.ImportThread.importStaticMaps: no data found for " + geocode); } diff --git a/main/src/cgeo/geocaching/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java index 167559d..7c3434e 100644 --- a/main/src/cgeo/geocaching/network/HtmlImage.java +++ b/main/src/cgeo/geocaching/network/HtmlImage.java @@ -92,7 +92,7 @@ public class HtmlImage implements Html.ImageGetter { // Background loading final private PublishSubject> loading = PublishSubject.create(); - final Observable waitForEnd = Observable.merge(loading).publish().refCount(); + final private Observable waitForEnd = Observable.merge(loading).publish().refCount(); final CompositeSubscription subscription = new CompositeSubscription(waitForEnd.subscribe()); final private Executor downloadExecutor = new ThreadPoolExecutor(10, 10, 5, TimeUnit.SECONDS, new LinkedBlockingQueue()); @@ -223,12 +223,12 @@ public class HtmlImage implements Html.ImageGetter { }); } - public void waitForBackgroundLoading(@Nullable final CancellableHandler handler) { + public Observable waitForEndObservable(@Nullable final CancellableHandler handler) { if (handler != null) { handler.unsubscribeIfCancelled(subscription); } loading.onCompleted(); - waitForEnd.toBlockingObservable().lastOrDefault(null); + return waitForEnd; } /** diff --git a/main/src/cgeo/geocaching/utils/RxUtils.java b/main/src/cgeo/geocaching/utils/RxUtils.java index deba573..a5cdc5f 100644 --- a/main/src/cgeo/geocaching/utils/RxUtils.java +++ b/main/src/cgeo/geocaching/utils/RxUtils.java @@ -1,6 +1,8 @@ package cgeo.geocaching.utils; +import rx.Observable; import rx.Scheduler; +import rx.observables.BlockingObservable; import rx.schedulers.Schedulers; public class RxUtils { @@ -9,4 +11,13 @@ public class RxUtils { private RxUtils() {} public final static Scheduler computationScheduler = Schedulers.computation(); + + public static void waitForCompletion(final BlockingObservable observable) { + observable.lastOrDefault(null); + return; + } + + public static void waitForCompletion(final Observable... observables) { + waitForCompletion(Observable.merge(observables).toBlockingObservable()); + } } -- cgit v1.1