Search code examples
androidosmdroidandroid-assets

Zooming in/out some tiles not rendering - Osmdroid offline maps


I'm loading tiles from asstets, these is my code, which initialize map:

    mapView = (MapView)findViewById(R.id.offline_map_view); 
    mapView.setClickable(true);
    mapView.setBuiltInZoomControls(false);
    mapView.setMaxZoomLevel(macroZoomLevel);
    mapView.setMinZoomLevel(macroZoomLevel);
    mapView.getController().setZoom(macroZoomLevel); //set initial zoom-level, depends on your need
    mapView.setTileSource(new XYTileSource("MapQuest", 0, 18, 256, ".png",new String[] {"file:///android_asset/try/"} ));
    mapView.setUseDataConnection(false); //keeps the mapView from loading online tiles usi1ng network connection.
    mapView.getController().setCenter(new GeoPoint(54.370958, 18.589210));
    giveMarkersForActualLevel();

and everything is ok till I try to zoom in, there are part of maps which not rendering properly. Then I zoom out and then area which was on the beginning rendered properly is now having some gray tiles.

Firstly, I used osmdroid 4.3, added in this way:

 compile 'org.osmdroid:osmdroid-android:4.3'

Then I try with newest version of osmdroid, importing it by method which is described on the website compile 'org.osmdroid:osmdroid-android:5.1@aar'

Then I read here tu build from sources so I download newest sources, build it by gradle and added aar file osmdroid-android-release.aar. This doesn't fix my issue, too.

After zoom in and zoom out, I'm removing markers and adding another ones, so I tried to refresh map in this way.

((View)mapView.getParent()).invalidate();
mapView.invalidate();
mapView.postInvalidate();

Marker startMarker = new Marker(mapView);
startMarker.setPosition(new GeoPoint(54.337385, 18.662132));
setPropertiesForTopMarker(startMarker);
mapView.getOverlays().add(startMarker);

Marker startMarker1 = new Marker(mapView);
startMarker1.setPosition(new GeoPoint(54.332781, 18.587932));
setPropertiesForTopMarker(startMarker1);
mapView.getOverlays().add(startMarker1);

mapView.invalidate();
((View)mapView.getParent()).invalidate();
mapView.invalidate();
mapView.postInvalidate();

but it doesn't work too.

Have you got any ideas, how this issue can be resolved?

EDITED:

I tried to build osmdroid from sources to change this values mentioned by @spy. The debug from my logcat looks ok. Here are logs. I can't paste it here, because there are too many lines.

I tried with adding tiles providers in this way:

 final IRegisterReceiver registerReceiver = new SimpleRegisterReceiver(getApplicationContext());

        final ITileSource tileSource = new XYTileSource("MapQuest", 12, 14, 256, ".png",new String[] {"file:///android_asset/MapQuest/"} );

        final MapTileFilesystemProvider fileSystemProvider = new MapTileFilesystemProvider(
                registerReceiver, tileSource);

        final MapTileProviderArray tileProviderArray = new MapTileProviderArray(
                tileSource, registerReceiver, new MapTileModuleProviderBase[] {
                fileSystemProvider});

        mapView = new MapView(this, new DefaultResourceProxyImpl(this), tileProviderArray); 

or this way

 final IRegisterReceiver registerReceiver = new SimpleRegisterReceiver(getApplicationContext());

            final ITileSource tileSource = new XYTileSource("MapQuest", 12, 14, 256, ".png",new String[] {"file:///android_asset/MapQuest/"} );

            final MapTileFilesystemProvider fileSystemProvider = new MapTileFilesystemProvider(
                    registerReceiver, tileSource);

            final MapTileProviderArray tileProviderArray = new MapTileProviderArray(
                    tileSource, registerReceiver, new MapTileModuleProviderBase[] {
                    fileSystemProvider});

 TilesOverlay tilesOverlay =
                new TilesOverlay(tileProviderArray, getApplicationContext());

        mapView.getOverlays().add(tilesOverlay);

but both methods didn't show me any map. Source of this code.


Solution

  • Ok, finally I solve my issue by using Providers.

    I made few modification of code taken from this answer, so right now it looks like this.

            mapView.setClickable(true);
            mapView.setBuiltInZoomControls(false);
    
            mapView.setMaxZoomLevel(macroZoomLevel);
            mapView.setMinZoomLevel(macroZoomLevel);
            mapView.getController().setZoom(macroZoomLevel); //set initial zoom-level, depends on your need
    
            mapView.setUseDataConnection(false); //keeps the mapView from loading online tiles usi1ng network connection.
            mapView.getController().setCenter(new GeoPoint(54.370958, 18.589210));
    
            // save zip to sd
            AssetManager assetManager = this.getAssets();
            InputStream is;
            String fileName = "map.zip";    // the zip file lies in assets root
            String path = this.getExternalFilesDir(null) + File.separator + fileName; // the path I save SD to
    
            File tileFile = new File(path);
            if(!tileFile.exists()) {
                try {
                    is = assetManager.open(fileName);
    
                    FileOutputStream fo = new FileOutputStream(path);
    
                    byte[] b = new byte[1024];
                    int length;
                    while((length = is.read(b)) != -1) {
                        fo.write(b, 0, length);
                    }
    
                    fo.flush();
                    fo.close();
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            IArchiveFile[] archives = new IArchiveFile[1];
            archives[0] = ArchiveFileFactory.getArchiveFile(tileFile);
    
            // Simple implementation that extends BitmapTileSourceBase and nothing else
            CustomTileSource customTiles = new CustomTileSource("MapQuest", null, 10, 14, 256, ".png");  // Maverik is the name of the folder inside the zip (so zip is map.zip and inside it is a folder called Maverik)
    
            MapTileModuleProviderBase[] providers = new MapTileModuleProviderBase[1];
            providers[0] = new MapTileFileArchiveProvider(new SimpleRegisterReceiver(this.getApplicationContext()), customTiles, archives);    // this one is for local tiles (zip etc.)
    
    
    
            MapTileProviderArray tileProvider = new MapTileProviderArray(customTiles,
                    new SimpleRegisterReceiver(this.getApplicationContext()), providers);
            tilesOverlay = new TilesOverlay(tileProvider, this.getApplicationContext());
            tilesOverlay.setLoadingBackgroundColor(Color.TRANSPARENT);  // this makes sure that the invisble tiles of local tiles are transparent so we can see tiles from web, transparent have a minor performance decline.
    
            mapView.getOverlays().add(tilesOverlay);
    

    CustomTileSource looks like this:

    public class CustomTileSource extends BitmapTileSourceBase {
    
        public CustomTileSource(String aName, ResourceProxy.string aResourceId, int aZoomMinLevel, int aZoomMaxLevel, int aTileSizePixels, String aImageFilenameEnding) {
            super(aName, aResourceId, aZoomMinLevel, aZoomMaxLevel, aTileSizePixels, aImageFilenameEnding);
        }
    }
    

    so this is just subclass of BitmapTileSourceBase without any additional method.

    I have in assets zip type file, which name is map.zip, structure of this directory looks like this:

    map.zip/MapQuest/[lvlOfZoom]/[x]/[y.png]
    

    And now it works ok, I only zooming when I click on my marker, the user by gesture can't do that.

    If you have some problems with implementing approach descripted by me or something isn't clear for you, I will try to help you in comments.