Update POI/transport loading thread and not interrupt main loading thread

This commit is contained in:
Victor Shcherb 2011-10-03 00:19:01 +02:00
commit bc6f8e4c72
11 changed files with 446 additions and 257 deletions

View file

@ -9,11 +9,15 @@ public class ToDoConstants {
// == Osmand application (TODO 127) ==
// TODO support cancelling poi search request! Do it in another thread (Check is cancelled()!!!) TODO transport progress
// TODO redesign Directions using GPX file! (One menu directions <-> switch 'Route')
// TODO test if voice properly inititialized (first command!)
// TODO prepare C++ version of routing algorithm
// Map Refactoring
// Remove notification from OsmAndMapTileView (?)
// Index version
// 1. POI inside obf
// 2. Multiple attributes for one point (amenity=circle, type=...)
@ -21,13 +25,9 @@ public class ToDoConstants {
// !|| 125 || Introduce service layer rather than singletons and put all related into new package (services). Review architecture. Split some big classes. ||
// === Common issues ===
// || 104 || Add activity to show current loaded indexes and information about them (Issue 366) ||
// || 123 || Improve gpx file showing (very slow for big files) (Issue 412) ||
// || 110 || Use android voice for pronounce command (could be used in future to pronounce street) (Issue 70) ||
// || 97 || For voice navigation consider current speed of vehicle. Especially when speed > 50 pronounce more than 200 m (Issue 420) ||
// || 111 || Investigate showing street name while driving (Issue 286) ||
// || 86 || Allow to add/edit custom tags to POI objects (Issue 44) ||
// || 92 || Support poi index with standard map index and unify POI categories (unify done +, works very slow) (Issue 417) ||
// || 113 || Calculate speed cameras/bumps on the road (announce about them) (Issue 418) ||
@ -43,13 +43,16 @@ public class ToDoConstants {
/////////////////////////// DONE //////////////////////////////
// DONE ANDROID :
// || 104 || Add activity to show current loaded indexes and information about them (Issue 366) ||
// || 112 || Investigate exiting/minimizing app (Issue 214) ||
// || 122 || Frozen sqlite db images (bug?). When images are loaded into sqlite the whole map is frozen (issue 413) ||
// || 120 || Show icons over poi circle (issue 414) ||
// || 119 || Dialog on main screen tips and tricks (Issue 415) ||
// || 118 || Config switching between maps on different zoom levels <14 (using raster), > 14 vector (Issue 419) ||
// || 124 || Animated transition using only raster images (?) - skip animations (!) - don not render vectoring for animations (Issue 238) ||
// || 92 || Support poi index with standard map index and unify POI categories (unify done +, works very slow) (Issue 417) ||
// || 97 || For voice navigation consider current speed of vehicle. Especially when speed > 50 pronounce more than 200 m (Issue 420) ||
// || 123 || Improve gpx file showing (very slow for big files) (Issue 412) ||
// DONE SWING
}

View file

@ -554,7 +554,6 @@ public class IndexPoiCreator extends AbstractIndexPartCreator {
}
public static void main(String[] args) throws SQLException, FileNotFoundException, IOException {
// TODO support cancelling poi search request! Do it in another thread (Check is cancelled()!!!)
long time = System.currentTimeMillis();
IndexPoiCreator poiCreator = new IndexPoiCreator();
// String fileSqlte = "/home/victor/projects/OsmAnd/data/osm-gen/POI/Ru-mow.poi.odb";

View file

@ -26,6 +26,6 @@ public interface AmenityIndexRepository {
String filterId, List<Amenity> toFill, boolean fillFound);
public void evaluateCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom,
PoiFilter filter, List<Amenity> toFill);
PoiFilter filter, ResultMatcher<Amenity> matcher);
}

View file

@ -141,11 +141,11 @@ public class AmenityIndexRepositoryBinary implements AmenityIndexRepository {
@Override
public void evaluateCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom,
PoiFilter filter, List<Amenity> toFill) {
cTopLatitude = topLatitude + (topLatitude - bottomLatitude);
cBottomLatitude = bottomLatitude - (topLatitude - bottomLatitude);
cLeftLongitude = leftLongitude - (rightLongitude - leftLongitude);
cRightLongitude = rightLongitude + (rightLongitude - leftLongitude);
PoiFilter filter, ResultMatcher<Amenity> matcher) {
cTopLatitude = topLatitude ;
cBottomLatitude = bottomLatitude ;
cLeftLongitude = leftLongitude ;
cRightLongitude = rightLongitude ;
cFilterId = filter == null ? null : filter.getFilterId();
cZoom = zoom;
// first of all put all entities in temp list in order to not freeze other read threads
@ -154,14 +154,12 @@ public class AmenityIndexRepositoryBinary implements AmenityIndexRepository {
int sright = MapUtils.get31TileNumberX(cRightLongitude);
int sbottom = MapUtils.get31TileNumberY(cBottomLatitude);
int stop = MapUtils.get31TileNumberY(cTopLatitude);
searchAmenities(stop, sleft, sbottom, sright, zoom, filter, tempList, null);
searchAmenities(stop, sleft, sbottom, sright, zoom, filter, tempList, matcher);
synchronized (this) {
cachedObjects.clear();
cachedObjects.addAll(tempList);
}
checkCachedAmenities(topLatitude, leftLongitude, bottomLatitude, rightLongitude, cZoom, filter.getFilterId(), toFill, true);
}

View file

@ -102,12 +102,14 @@ public class AmenityIndexRepositoryOdb extends BaseLocationIndexRepository<Ameni
cFilterId = null;
}
public void evaluateCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, PoiFilter filter, List<Amenity> toFill){
cTopLatitude = topLatitude + (topLatitude -bottomLatitude);
cBottomLatitude = bottomLatitude - (topLatitude -bottomLatitude);
cLeftLongitude = leftLongitude - (rightLongitude - leftLongitude);
cRightLongitude = rightLongitude + (rightLongitude - leftLongitude);
cFilterId = filter == null? null :filter.getFilterId();
@Override
public void evaluateCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom,
PoiFilter filter, ResultMatcher<Amenity> matcher) {
cTopLatitude = topLatitude;
cBottomLatitude = bottomLatitude;
cLeftLongitude = leftLongitude;
cRightLongitude = rightLongitude;
cFilterId = filter == null ? null : filter.getFilterId();
cZoom = zoom;
// first of all put all entities in temp list in order to not freeze other read threads
ArrayList<Amenity> tempList = new ArrayList<Amenity>();
@ -115,13 +117,11 @@ public class AmenityIndexRepositoryOdb extends BaseLocationIndexRepository<Ameni
int sright = MapUtils.get31TileNumberX(cRightLongitude);
int sbottom = MapUtils.get31TileNumberY(cBottomLatitude);
int stop = MapUtils.get31TileNumberY(cTopLatitude);
searchAmenities(stop, sleft, sbottom, sright, cZoom, filter, tempList, null);
searchAmenities(stop, sleft, sbottom, sright, cZoom, filter, tempList, matcher);
synchronized (this) {
cachedObjects.clear();
cachedObjects.addAll(tempList);
}
checkCachedAmenities(topLatitude, leftLongitude, bottomLatitude, rightLongitude, cZoom, filter.getFilterId(), toFill);
}
public synchronized boolean checkCachedAmenities(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, String filterId, List<Amenity> toFill, boolean fillFound){

View file

@ -0,0 +1,339 @@
package net.osmand.plus;
import java.io.File;
import java.util.List;
import java.util.Stack;
import org.apache.commons.logging.Log;
import android.os.Handler;
import android.os.Looper;
import net.osmand.Algoritms;
import net.osmand.LogUtil;
import net.osmand.ResultMatcher;
import net.osmand.data.Amenity;
import net.osmand.data.MapTileDownloader;
import net.osmand.data.TransportStop;
import net.osmand.data.MapTileDownloader.DownloadRequest;
import net.osmand.data.MapTileDownloader.IMapDownloaderCallback;
import net.osmand.map.ITileSource;
/**
* Thread to load map objects (POI, transport stops )async
*/
public class AsyncLoadingThread extends Thread {
public static final int LIMIT_TRANSPORT = 200;
private static final Log log = LogUtil.getLog(AsyncLoadingThread.class);
private Handler asyncLoadingPoi;
private Handler asyncLoadingTransport;
Stack<Object> requests = new Stack<Object>();
AmenityLoadRequest poiLoadRequest = null;
TransportLoadRequest transportLoadRequest = null;
private static final MapTileDownloader downloader = MapTileDownloader.getInstance();
private final ResourceManager resourceManger;
public AsyncLoadingThread(ResourceManager resourceManger) {
super("Loader map objects (synchronizer)"); //$NON-NLS-1$
this.resourceManger = resourceManger;
}
private void startPoiLoadingThread() {
if (asyncLoadingPoi == null) {
Thread th = new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
asyncLoadingPoi = new Handler();
Looper.loop();
}
}, "Loading poi");
th.start();
}
while(asyncLoadingPoi != null){
// wait
}
}
private void startTransportLoadingThread() {
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
asyncLoadingTransport = new Handler();
Looper.loop();
}
}, "Loading transport").start();
while(asyncLoadingTransport != null){
// wait
}
}
private int calculateProgressStatus(){
int progress = 0;
if (downloader.isSomethingBeingDownloaded()) {
progress = BusyIndicator.STATUS_GREEN;
} else if (resourceManger.getContext().getRoutingHelper().isRouteBeingCalculated()) {
progress = BusyIndicator.STATUS_BLUE;
} else if (!requests.isEmpty()) {
progress = BusyIndicator.STATUS_BLACK;
} else if(poiLoadRequest != null && !poiLoadRequest.isFinished()) {
progress = BusyIndicator.STATUS_BLACK;
} else if(transportLoadRequest != null && !transportLoadRequest.isFinished()) {
progress = BusyIndicator.STATUS_BLACK;
}
return progress;
}
@Override
public void run() {
while (true) {
try {
boolean tileLoaded = false;
boolean amenityLoaded = false;
boolean transportLoaded = false;
boolean mapLoaded = false;
int progress = calculateProgressStatus();
synchronized (resourceManger) {
if (resourceManger.getBusyIndicator() != null) {
resourceManger.getBusyIndicator().updateStatus(progress);
}
}
while (!requests.isEmpty()) {
Object req = requests.pop();
if (req instanceof TileLoadDownloadRequest) {
TileLoadDownloadRequest r = (TileLoadDownloadRequest) req;
tileLoaded |= resourceManger.getRequestedImageTile(r) != null;
} else if (req instanceof AmenityLoadRequest) {
if (!amenityLoaded) {
if (poiLoadRequest == null || asyncLoadingPoi == null) {
startPoiLoadingThread();
poiLoadRequest = (AmenityLoadRequest) req;
asyncLoadingPoi.post(poiLoadRequest.prepareToRun());
} else if (poiLoadRequest.recalculateRequest((AmenityLoadRequest) req)) {
poiLoadRequest = (AmenityLoadRequest) req;
asyncLoadingPoi.post(poiLoadRequest.prepareToRun());
}
amenityLoaded = true;
}
} else if (req instanceof TransportLoadRequest) {
if (!transportLoaded) {
if (transportLoadRequest == null || asyncLoadingTransport == null) {
startTransportLoadingThread();
transportLoadRequest = (TransportLoadRequest) req;
asyncLoadingTransport.post(transportLoadRequest.prepareToRun());
} else if (transportLoadRequest.recalculateRequest((TransportLoadRequest) req)) {
transportLoadRequest = (TransportLoadRequest) req;
asyncLoadingTransport.post(transportLoadRequest.prepareToRun());
}
transportLoaded = true;
}
} else if (req instanceof MapLoadRequest) {
if (!mapLoaded) {
MapLoadRequest r = (MapLoadRequest) req;
resourceManger.getRenderer().loadMap(r.tileBox, downloader.getDownloaderCallbacks());
mapLoaded = true;
}
}
}
if (tileLoaded || amenityLoaded || transportLoaded || mapLoaded) {
// use downloader callback
for (IMapDownloaderCallback c : downloader.getDownloaderCallbacks()) {
c.tileDownloaded(null);
}
}
int newProgress = calculateProgressStatus();
if (progress != newProgress) {
synchronized (resourceManger) {
if (resourceManger.getBusyIndicator() != null) {
resourceManger.getBusyIndicator().updateStatus(newProgress);
}
}
}
sleep(750);
} catch (InterruptedException e) {
log.error(e, e);
} catch (RuntimeException e) {
log.error(e, e);
}
}
}
public void requestToLoadImage(TileLoadDownloadRequest req) {
requests.push(req);
}
public void requestToLoadAmenities(AmenityLoadRequest req) {
requests.push(req);
}
public void requestToLoadMap(MapLoadRequest req) {
requests.push(req);
}
public void requestToLoadTransport(TransportLoadRequest req) {
requests.push(req);
}
public boolean isFileCurrentlyDownloaded(File fileToSave) {
return downloader.isFileCurrentlyDownloaded(fileToSave);
}
public void requestToDownload(TileLoadDownloadRequest req) {
downloader.requestToDownload(req);
}
protected static class TileLoadDownloadRequest extends DownloadRequest {
public final String tileId;
public final File dirWithTiles;
public final ITileSource tileSource;
public TileLoadDownloadRequest(File dirWithTiles, String url, File fileToSave, String tileId, ITileSource source, int tileX,
int tileY, int zoom) {
super(url, fileToSave, tileX, tileY, zoom);
this.dirWithTiles = dirWithTiles;
this.tileSource = source;
this.tileId = tileId;
}
}
protected static class MapObjectLoadRequest<T> implements ResultMatcher<T> {
protected double topLatitude;
protected double bottomLatitude;
protected double leftLongitude;
protected double rightLongitude;
protected boolean cancelled = false;
protected volatile boolean finished = false;
public boolean isContains(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude) {
boolean inside = this.topLatitude >= topLatitude && this.leftLongitude <= leftLongitude
&& this.rightLongitude >= rightLongitude && this.bottomLatitude <= bottomLatitude;
return inside;
}
public void setBoundaries(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude) {
this.topLatitude = topLatitude;
this.bottomLatitude = bottomLatitude;
this.leftLongitude = leftLongitude;
this.rightLongitude = rightLongitude;
}
public boolean isFinished() {
return finished;
}
public void finish() {
finished = true;
// use downloader callback
for (IMapDownloaderCallback c : downloader.getDownloaderCallbacks()) {
c.tileDownloaded(null);
}
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public boolean publish(T object) {
return true;
}
}
protected static class AmenityLoadRequest extends MapObjectLoadRequest<Amenity> {
private final List<AmenityIndexRepository> res;
private final PoiFilter filter;
private final int zoom;
public AmenityLoadRequest(List<AmenityIndexRepository> repos, int zoom, PoiFilter filter) {
super();
this.res = repos;
this.zoom = zoom;
this.filter = filter;
}
public Runnable prepareToRun() {
final double ntopLatitude = topLatitude + (topLatitude - bottomLatitude) / 2;
final double nbottomLatitude = bottomLatitude - (topLatitude - bottomLatitude) / 2;
final double nleftLongitude = leftLongitude - (rightLongitude - leftLongitude) / 2;
final double nrightLongitude = rightLongitude + (rightLongitude - leftLongitude) / 2;
setBoundaries(ntopLatitude, nleftLongitude, nbottomLatitude, nrightLongitude);
return new Runnable() {
@Override
public void run() {
for (AmenityIndexRepository repository : res) {
repository.evaluateCachedAmenities(ntopLatitude, nleftLongitude, nbottomLatitude, nrightLongitude, zoom, filter,
AmenityLoadRequest.this);
}
finish();
}
};
}
public boolean recalculateRequest(AmenityLoadRequest req) {
if (this.zoom != req.zoom || !Algoritms.objectEquals(this.filter, req.filter)) {
return true;
}
return !isContains(req.topLatitude, req.leftLongitude, req.bottomLatitude, req.rightLongitude);
}
}
protected static class TransportLoadRequest extends MapObjectLoadRequest<TransportStop> {
private final List<TransportIndexRepository> repos;
private int zoom;
public TransportLoadRequest(List<TransportIndexRepository> repos, int zoom) {
super();
this.repos = repos;
this.zoom = zoom;
}
public Runnable prepareToRun() {
final double ntopLatitude = topLatitude + (topLatitude - bottomLatitude) / 2;
final double nbottomLatitude = bottomLatitude - (topLatitude - bottomLatitude) / 2;
final double nleftLongitude = leftLongitude - (rightLongitude - leftLongitude) / 2;
final double nrightLongitude = rightLongitude + (rightLongitude - leftLongitude) / 2;
setBoundaries(ntopLatitude, nleftLongitude, nbottomLatitude, nrightLongitude);
return new Runnable() {
@Override
public void run() {
for (TransportIndexRepository repository : repos) {
repository.evaluateCachedTransportStops(ntopLatitude, nleftLongitude, nbottomLatitude, nrightLongitude, zoom,
LIMIT_TRANSPORT, TransportLoadRequest.this);
}
finish();
}
};
}
public boolean recalculateRequest(TransportLoadRequest req) {
if (this.zoom != req.zoom) {
return true;
}
return !isContains(req.topLatitude, req.leftLongitude, req.bottomLatitude, req.rightLongitude);
}
}
protected static class MapLoadRequest {
public final RotatedTileBox tileBox;
public MapLoadRequest(RotatedTileBox tileBox) {
super();
this.tileBox = tileBox;
}
}
}

View file

@ -15,7 +15,6 @@ import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.TreeMap;
import net.osmand.Algoritms;
@ -27,13 +26,15 @@ import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.data.Amenity;
import net.osmand.data.AmenityType;
import net.osmand.data.IndexConstants;
import net.osmand.data.MapTileDownloader;
import net.osmand.data.TransportStop;
import net.osmand.data.MapTileDownloader.DownloadRequest;
import net.osmand.data.MapTileDownloader.IMapDownloaderCallback;
import net.osmand.map.ITileSource;
import net.osmand.osm.LatLon;
import net.osmand.osm.MapUtils;
import net.osmand.plus.AsyncLoadingThread.AmenityLoadRequest;
import net.osmand.plus.AsyncLoadingThread.MapLoadRequest;
import net.osmand.plus.AsyncLoadingThread.TileLoadDownloadRequest;
import net.osmand.plus.AsyncLoadingThread.TransportLoadRequest;
import net.osmand.plus.activities.OsmandApplication;
import net.osmand.plus.render.BaseOsmandRender;
import net.osmand.plus.render.MapRenderRepositories;
@ -70,7 +71,6 @@ public class ResourceManager {
public static final String TEMP_SOURCE_TO_LOAD = "temp"; //$NON-NLS-1$
public static final String VECTOR_MAP = "#vector_map"; //$NON-NLS-1$
public static final int LIMIT_TRANSPORT = 200;
private static final Log log = LogUtil.getLog(ResourceManager.class);
private static final String MINE_POI_DB = APP_DIR + "mine"+ IndexConstants.POI_INDEX_EXT;
@ -92,7 +92,7 @@ public class ResourceManager {
private BusyIndicator busyIndicator;
private final MapTileDownloader downloader = MapTileDownloader.getInstance();
// Indexes
private final Map<String, RegionAddressRepository> addressMap = new TreeMap<String, RegionAddressRepository>(Collator.getInstance());
@ -107,20 +107,18 @@ public class ResourceManager {
protected final MapRenderRepositories renderer;
public final AsyncLoadingThread asyncLoadingTiles = new AsyncLoadingThread();
public final AsyncLoadingThread asyncLoadingThread = new AsyncLoadingThread(this);
protected boolean internetIsNotAccessible = false;
protected AmenityIndexRepositoryOdb updatablePoiDb = null;
public ResourceManager(OsmandApplication context) {
this.context = context;
this.renderer = new MapRenderRepositories(context);
asyncLoadingTiles.start();
asyncLoadingThread.start();
resetStoreDirectory();
WindowManager mgr = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
mgr.getDefaultDisplay().getMetrics(dm);
@ -131,6 +129,7 @@ public class ResourceManager {
maxImgCacheSize = (int) (tiles) ;
}
public void resetStoreDirectory() {
dirWithTiles = context.getSettings().extendOsmandPath(TILES_PATH);
dirWithTiles.mkdirs();
@ -283,7 +282,8 @@ public class ResourceManager {
}
if (loadFromFs && cacheOfImages.get(tileId) == null && map != null) {
if(!loadFromInternetIfNeeded && !tileExistOnFileSystem(tileId, map, x, y, zoom)){
boolean locked = map instanceof SQLiteTileSource && ((SQLiteTileSource) map).isLocked();
if(!loadFromInternetIfNeeded && !locked && !tileExistOnFileSystem(tileId, map, x, y, zoom)){
return null;
}
String url = loadFromInternetIfNeeded ? map.getUrlToLoad(x, y, zoom) : null;
@ -300,7 +300,7 @@ public class ResourceManager {
if(sync){
return getRequestedImageTile(req);
} else {
asyncLoadingTiles.requestToLoadImage(req);
asyncLoadingThread.requestToLoadImage(req);
}
}
return cacheOfImages.get(tileId);
@ -308,14 +308,18 @@ public class ResourceManager {
private Bitmap getRequestedImageTile(TileLoadDownloadRequest req){
protected Bitmap getRequestedImageTile(TileLoadDownloadRequest req){
if(req.tileId == null || req.dirWithTiles == null){
return null;
}
Bitmap cacheBmp = cacheOfImages.get(req.tileId);
if (cacheBmp != null) {
return cacheBmp;
}
if (cacheOfImages.size() > maxImgCacheSize) {
clearTiles();
}
if (req.dirWithTiles.canRead() && !downloader.isFileCurrentlyDownloaded(req.fileToSave)) {
if (req.dirWithTiles.canRead() && !asyncLoadingThread.isFileCurrentlyDownloaded(req.fileToSave)) {
long time = System.currentTimeMillis();
if (log.isDebugEnabled()) {
log.debug("Start loaded file : " + req.tileId + " " + Thread.currentThread().getName()); //$NON-NLS-1$ //$NON-NLS-2$
@ -343,7 +347,7 @@ public class ResourceManager {
}
if (cacheOfImages.get(req.tileId) == null && req.url != null) {
downloader.requestToDownload(req);
asyncLoadingThread.requestToDownload(req);
}
}
@ -667,18 +671,22 @@ public class ResourceManager {
toFill.add(a);
}
}
} else {
String filterId = filter == null ? null : filter.getFilterId();
List<AmenityIndexRepository> repos = new ArrayList<AmenityIndexRepository>();
for (AmenityIndexRepository index : amenityRepositories) {
if (index.checkContains(topLatitude, leftLongitude, bottomLatitude, rightLongitude)) {
if (!index.checkCachedAmenities(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom, filterId, toFill,
true)) {
asyncLoadingTiles.requestToLoadAmenities(new AmenityLoadRequest(index, topLatitude, leftLongitude, bottomLatitude,
rightLongitude, zoom, filter));
repos.add(index);
}
}
}
if(!repos.isEmpty()){
AmenityLoadRequest req = new AmenityLoadRequest(repos, zoom, filter);
req.setBoundaries(topLatitude, leftLongitude, bottomLatitude, rightLongitude);
asyncLoadingThread.requestToLoadAmenities(req);
}
}
}
@ -705,14 +713,19 @@ public class ResourceManager {
public void searchTransportAsync(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, List<TransportStop> toFill){
for(TransportIndexRepository index : transportRepositories){
if(index.checkContains(topLatitude, leftLongitude, bottomLatitude, rightLongitude)){
if(!index.checkCachedObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom, toFill, true)){
asyncLoadingTiles.requestToLoadTransport(
new TransportLoadRequest(index, topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom));
List<TransportIndexRepository> repos = new ArrayList<TransportIndexRepository>();
for (TransportIndexRepository index : transportRepositories) {
if (index.checkContains(topLatitude, leftLongitude, bottomLatitude, rightLongitude)) {
if (!index.checkCachedObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom, toFill, true)) {
repos.add(index);
}
}
}
if(!repos.isEmpty()){
TransportLoadRequest req = new TransportLoadRequest(repos, zoom);
req.setBoundaries(topLatitude, leftLongitude, bottomLatitude, rightLongitude);
asyncLoadingThread.requestToLoadTransport(req);
}
}
////////////////////////////////////////////// Working with map ////////////////////////////////////////////////
@ -722,7 +735,7 @@ public class ResourceManager {
public void updateRendererMap(RotatedTileBox rotatedTileBox){
renderer.interruptLoadingMap();
asyncLoadingTiles.requestToLoadMap(
asyncLoadingThread.requestToLoadMap(
new MapLoadRequest(new RotatedTileBox(rotatedTileBox)));
}
@ -820,185 +833,12 @@ public class ResourceManager {
}
protected synchronized void clearTiles(){
protected synchronized void clearTiles() {
log.info("Cleaning tiles - size = " + cacheOfImages.size()); //$NON-NLS-1$
ArrayList<String> list = new ArrayList<String>(cacheOfImages.keySet());
// remove first images (as we think they are older)
for (int i = 0; i < list.size() /2; i ++) {
for (int i = 0; i < list.size() / 2; i++) {
cacheOfImages.remove(list.get(i));
}
}
private static class TileLoadDownloadRequest extends DownloadRequest {
public final String tileId;
public final File dirWithTiles;
public final ITileSource tileSource;
public TileLoadDownloadRequest(File dirWithTiles, String url, File fileToSave,
String tileId, ITileSource source, int tileX, int tileY, int zoom) {
super(url, fileToSave, tileX, tileY, zoom);
this.dirWithTiles = dirWithTiles;
this.tileSource = source;
this.tileId = tileId;
}
}
private static class AmenityLoadRequest {
public final AmenityIndexRepository repository;
public final double topLatitude;
public final double bottomLatitude;
public final double leftLongitude;
public final double rightLongitude;
public final PoiFilter filter;
public final int zoom;
public AmenityLoadRequest(AmenityIndexRepository repository, double topLatitude, double leftLongitude,
double bottomLatitude, double rightLongitude, int zoom, PoiFilter filter) {
super();
this.bottomLatitude = bottomLatitude;
this.leftLongitude = leftLongitude;
this.repository = repository;
this.rightLongitude = rightLongitude;
this.topLatitude = topLatitude;
this.zoom = zoom;
this.filter = filter;
}
}
private static class TransportLoadRequest {
public final TransportIndexRepository repository;
public final double topLatitude;
public final double bottomLatitude;
public final double leftLongitude;
public final double rightLongitude;
public final int zoom;
public TransportLoadRequest(TransportIndexRepository repository, double topLatitude, double leftLongitude,
double bottomLatitude, double rightLongitude, int zoom) {
super();
this.bottomLatitude = bottomLatitude;
this.leftLongitude = leftLongitude;
this.repository = repository;
this.rightLongitude = rightLongitude;
this.topLatitude = topLatitude;
this.zoom = zoom;
}
}
private static class MapLoadRequest {
public final RotatedTileBox tileBox;
public MapLoadRequest(RotatedTileBox tileBox) {
super();
this.tileBox = tileBox;
}
}
public class AsyncLoadingThread extends Thread {
Stack<Object> requests = new Stack<Object>();
public AsyncLoadingThread(){
super("Loader map objects (tiles, poi)"); //$NON-NLS-1$
}
@Override
public void run() {
while(true){
try {
boolean update = false;
boolean amenityLoaded = false;
boolean transportLoaded = false;
boolean mapLoaded = false;
int progress = 0;
if(downloader.isSomethingBeingDownloaded()){
progress = BusyIndicator.STATUS_GREEN;
}
synchronized(ResourceManager.this){
if(busyIndicator != null){
if(context.getRoutingHelper().isRouteBeingCalculated()){
progress = BusyIndicator.STATUS_BLUE;
} else if(!requests.isEmpty()){
progress = BusyIndicator.STATUS_BLACK;;
}
busyIndicator.updateStatus(progress);
}
}
while(!requests.isEmpty()){
Object req = requests.pop();
if (req instanceof TileLoadDownloadRequest) {
TileLoadDownloadRequest r = (TileLoadDownloadRequest) req;
if (cacheOfImages.get(r.tileId) == null) {
update |= getRequestedImageTile(r) != null;
}
} else if(req instanceof AmenityLoadRequest){
if(!amenityLoaded){
AmenityLoadRequest r = (AmenityLoadRequest) req;
r.repository.evaluateCachedAmenities(r.topLatitude, r.leftLongitude,
r.bottomLatitude, r.rightLongitude, r.zoom, r.filter, null);
amenityLoaded = true;
}
} else if(req instanceof TransportLoadRequest){
if(!transportLoaded){
TransportLoadRequest r = (TransportLoadRequest) req;
r.repository.evaluateCachedTransportStops(r.topLatitude, r.leftLongitude,
r.bottomLatitude, r.rightLongitude, r.zoom, LIMIT_TRANSPORT, null);
transportLoaded = true;
}
} else if(req instanceof MapLoadRequest){
if(!mapLoaded){
MapLoadRequest r = (MapLoadRequest) req;
renderer.loadMap(r.tileBox, downloader.getDownloaderCallbacks());
mapLoaded = true;
}
}
}
if(update || amenityLoaded || transportLoaded || mapLoaded){
// use downloader callback
for(IMapDownloaderCallback c : downloader.getDownloaderCallbacks()){
c.tileDownloaded(null);
}
}
boolean routeBeingCalculated = context.getRoutingHelper().isRouteBeingCalculated();
if (progress != 0 || routeBeingCalculated || downloader.isSomethingBeingDownloaded()) {
synchronized (ResourceManager.this) {
if (busyIndicator != null) {
if(routeBeingCalculated){
progress = BusyIndicator.STATUS_BLUE;
} else if(downloader.isSomethingBeingDownloaded()){
progress = BusyIndicator.STATUS_GREEN;
} else {
progress = 0;
}
busyIndicator.updateStatus(progress);
}
}
}
sleep(750);
} catch (InterruptedException e) {
log.error(e, e);
} catch (RuntimeException e){
log.error(e, e);
}
}
}
public void requestToLoadImage(TileLoadDownloadRequest req){
requests.push(req);
}
public void requestToLoadAmenities(AmenityLoadRequest req){
requests.push(req);
}
public void requestToLoadMap(MapLoadRequest req){
requests.push(req);
}
public void requestToLoadTransport(TransportLoadRequest req){
requests.push(req);
}
};
}
}

View file

@ -34,7 +34,6 @@ public class SQLiteTileSource implements ITileSource {
private final File file;
private int minZoom = 1;
private int maxZoom = 17;
private boolean locked = false;
public SQLiteTileSource(File f, List<TileSourceTemplate> toFindUrl){
this.file = f;
@ -185,7 +184,11 @@ public class SQLiteTileSource implements ITileSource {
}
public boolean isLocked() {
return locked;
SQLiteDatabase db = getDatabase();
if(db == null){
return false;
}
return db.isDbLockedByOtherThreads();
}
public Bitmap getImage(int x, int y, int zoom) {
@ -219,36 +222,35 @@ public class SQLiteTileSource implements ITileSource {
private final int BUF_SIZE = 1024;
public void insertImage(int x, int y, int zoom, File fileToSave) throws IOException {
/**
* Makes method synchronized to give a little more time for get methods and
* let all writing attempts to wait outside of this method
*/
public synchronized void insertImage(int x, int y, int zoom, File fileToSave) throws IOException {
SQLiteDatabase db = getDatabase();
if(db == null || db.isReadOnly()){
if (db == null || db.isReadOnly()) {
return;
}
if(exists(x, y, zoom)){
if (exists(x, y, zoom)) {
return;
}
try {
locked = true;
ByteBuffer buf = ByteBuffer.allocate((int) fileToSave.length());
FileInputStream is = new FileInputStream(fileToSave);
int i = 0;
byte[] b = new byte[BUF_SIZE];
while ((i = is.read(b, 0, BUF_SIZE)) > -1) {
buf.put(b, 0, i);
}
ByteBuffer buf = ByteBuffer.allocate((int) fileToSave.length());
FileInputStream is = new FileInputStream(fileToSave);
int i = 0;
byte[] b = new byte[BUF_SIZE];
while ((i = is.read(b, 0, BUF_SIZE)) > -1) {
buf.put(b, 0, i);
}
SQLiteStatement statement = db.compileStatement("INSERT INTO tiles VALUES(?, ?, ?, ?, ?)"); //$NON-NLS-1$
statement.bindLong(1, x);
statement.bindLong(2, y);
statement.bindLong(3, 17 - zoom);
statement.bindLong(4, 0);
statement.bindBlob(5, buf.array());
statement.execute();
statement.close();
SQLiteStatement statement = db.compileStatement("INSERT INTO tiles VALUES(?, ?, ?, ?, ?)"); //$NON-NLS-1$
statement.bindLong(1, x);
statement.bindLong(2, y);
statement.bindLong(3, 17 - zoom);
statement.bindLong(4, 0);
statement.bindBlob(5, buf.array());
statement.execute();
statement.close();
} finally {
locked = false;
}
}
public void closeDB(){

View file

@ -2,6 +2,7 @@ package net.osmand.plus;
import java.util.List;
import net.osmand.ResultMatcher;
import net.osmand.data.TransportRoute;
import net.osmand.data.TransportStop;
import net.osmand.osm.LatLon;
@ -27,7 +28,8 @@ public interface TransportIndexRepository {
public List<String> getRouteDescriptionsForStop(TransportStop stop, String format);
public void evaluateCachedTransportStops(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, int limit, List<TransportStop> toFill);
public void evaluateCachedTransportStops(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, int limit,
ResultMatcher<TransportStop> matcher);
public List<RouteInfoLocation> searchTransportRouteStops(double latitude, double longitude, LatLon locationToGo, int zoom);

View file

@ -10,6 +10,7 @@ import java.util.List;
import java.util.Map;
import net.osmand.LogUtil;
import net.osmand.ResultMatcher;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
import net.osmand.data.TransportRoute;
@ -43,10 +44,12 @@ public class TransportIndexRepositoryBinary implements TransportIndexRepository
return file.containTransportData(topLatitude, leftLongitude, bottomLatitude, rightLongitude);
}
@Override
public boolean checkCachedObjects(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, List<TransportStop> toFill){
return checkCachedObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude, zoom, toFill, false);
}
@Override
public synchronized boolean checkCachedObjects(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude, int zoom, List<TransportStop> toFill, boolean fillFound){
boolean inside = cTopLatitude >= topLatitude && cLeftLongitude <= leftLongitude && cRightLongitude >= rightLongitude
&& cBottomLatitude <= bottomLatitude && cZoom == zoom;
@ -64,7 +67,7 @@ public class TransportIndexRepositoryBinary implements TransportIndexRepository
}
public List<TransportStop> searchTransportStops(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude,
int limit, List<TransportStop> stops) {
int limit, List<TransportStop> stops, ResultMatcher<TransportStop> matcher) {
long now = System.currentTimeMillis();
try {
file.searchTransportIndex(BinaryMapIndexReader.buildSearchTransportRequest(MapUtils.get31TileNumberX(leftLongitude),
@ -88,6 +91,7 @@ public class TransportIndexRepositoryBinary implements TransportIndexRepository
* 0} - ref, {1} - type, {2} - name, {3} - name_en
* @return null if something goes wrong
*/
@Override
public List<String> getRouteDescriptionsForStop(TransportStop stop, String format) {
assert acceptTransportStop(stop);
long now = System.currentTimeMillis();
@ -114,8 +118,9 @@ public class TransportIndexRepositoryBinary implements TransportIndexRepository
return res;
}
@Override
public void evaluateCachedTransportStops(double topLatitude, double leftLongitude, double bottomLatitude, double rightLongitude,
int zoom, int limit, List<TransportStop> toFill) {
int zoom, int limit, ResultMatcher<TransportStop> matcher) {
cTopLatitude = topLatitude + (topLatitude - bottomLatitude);
cBottomLatitude = bottomLatitude - (topLatitude - bottomLatitude);
cLeftLongitude = leftLongitude - (rightLongitude - leftLongitude);
@ -123,16 +128,15 @@ public class TransportIndexRepositoryBinary implements TransportIndexRepository
cZoom = zoom;
// first of all put all entities in temp list in order to not freeze other read threads
ArrayList<TransportStop> tempList = new ArrayList<TransportStop>();
searchTransportStops(cTopLatitude, cLeftLongitude, cBottomLatitude, cRightLongitude, limit, tempList);
searchTransportStops(cTopLatitude, cLeftLongitude, cBottomLatitude, cRightLongitude, limit, tempList, matcher);
synchronized (this) {
cachedObjects.clear();
cachedObjects.addAll(tempList);
}
checkCachedObjects(topLatitude, leftLongitude, bottomLatitude, rightLongitude, cZoom, toFill);
}
@Override
public List<RouteInfoLocation> searchTransportRouteStops(double latitude, double longitude, LatLon locationToGo, int zoom) {
long now = System.currentTimeMillis();
final LatLon loc = new LatLon(latitude, longitude);

View file

@ -152,7 +152,9 @@ public class DownloadTilesDialog {
instance.addDownloaderCallback(new IMapDownloaderCallback(){
@Override
public void tileDownloaded(DownloadRequest request) {
progressDlg.setProgress(progressDlg.getProgress() + 1);
if (request != null) {
progressDlg.setProgress(progressDlg.getProgress() + 1);
}
}
});