1

After your comment JaakL I did a bit of work and this is as far as I got. Unfortunately, it's not working yet. I did step by step what you told me but every time I load the app I just get a white screen instead of the beautiful map I'm trying to load.

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    MapView mapView;
    mapView=(MapView)findViewById(R.id.mapView);



    // Optional, but very useful: restore map state during device rotation,
    // it is saved in onRetainNonConfigurationInstance() below
    Components retainObject = (Components) getLastNonConfigurationInstance();
    if (retainObject != null) {
        // just restore configuration and update listener, skip other initializations

        mapView.setComponents(retainObject);

        return;
    } else {
        // 2. create and set MapView components - mandatory

        mapView.setComponents(new Components());
    }

        copyAssets();

        try {
            MBTilesRasterDataSource dataSource = new MBTilesRasterDataSource(
                    new EPSG3857(), 0, 19,
                    (null).getAbsolutePath() + "/braga.mbtiles",
                    false, this);
            RasterLayer mbLayer = new RasterLayer(dataSource, 0);
            mapView.getLayers().addLayer(mbLayer);
        } catch (IOException e) {
            Log.error(e.getMessage());
        }

First three lines of my debugger :

        27337-27337/com.exaple.myapplication5.app E/Trace﹕ error opening trace file: No such file or directory (2)
        27337-27337/com.exaple.myapplication5.app W/ActivityThread﹕ Application    com.exaple.myapplication5.app is waiting for the debugger on port 8100...
        27337-27337/com.exaple.myapplication5.app I/System.out﹕ Sending WAIT chunk
NetworkzZz
  • 49
  • 1
  • 8

2 Answers2

2

The trick is that you need to copy the file from application package to device storage, otherwise you cannot open the MBtiles file.

  1. Put your map.mbtiles file to /assets folder, not to res/raw/
  2. Copy the file during first application start. I'd just call copyAssets() in your onCreate() method. See code below, this copies everything under assets to app private folder. Note that you may want to add handling of typical file write issue cases there: SD card not available, no permission to write (your app must have WRITE_EXTERNAL_STORAGE permission), not enough space, maybe something more.
  3. Create datasource and layer with right path:

Sample code:

@Override
public void onCreate(Bundle savedInstanceState) {
  // create mapview, settings...

    copyAssets();
    try {
        MBTilesRasterDataSource dataSource = new MBTilesRasterDataSource(
            new EPSG3857(), 0, 19, 
            getExternalFilesDir(null).getAbsolutePath()+"/map.mbtiles",
            false, this);
        RasterLayer mbLayer = new RasterLayer(dataSource, 0);
        // use setBaseLayer() if this is main layer, addLayer() if it is overlay layer
        mapView.getLayers().setBaseLayer(mbLayer);

        // recenter map to coverage
        HashMap<String, String> dbMetaData = dataSource.getDatabase().getMetadata();

        String center = dbMetaData.get("center");
        String bounds = dbMetaData.get("bounds");
        if(center != null){
            // format: long,lat,zoom
            String[] centerParams = center.split(",");
            mapView.setFocusPoint(mapView.getLayers().getBaseLayer().getProjection().fromWgs84(Double.parseDouble(centerParams[0]), Double.parseDouble(centerParams[1])));
            mapView.setZoom(Float.parseFloat(centerParams[2]));
            Log.debug ("center to point "+Arrays.toString(centerParams));
        }else if(bounds != null){
            // format: longMin,latMin,longMax,latMax
            String[] boundsParams = bounds.split(",");
            MapPos bottomLeft = mapView.getLayers().getBaseProjection().fromWgs84(Double.parseDouble(boundsParams[0]), Double.parseDouble(boundsParams[1]));
            MapPos topRight = mapView.getLayers().getBaseProjection().fromWgs84(Double.parseDouble(boundsParams[2]), Double.parseDouble(boundsParams[3]));
            Log.debug ("center to bounds "+bottomLeft.x+","+topRight.y+","+topRight.x+","+bottomLeft.y);
            mapView.setBoundingBox(new Bounds(bottomLeft.x,topRight.y,topRight.x,bottomLeft.y), false);

            // check that zoom is within given range
            int[] zoomRange = dataSource.getDatabase().getZoomRange();
            if(mapView.getZoom() < zoomRange[0]){
                mapView.setZoom(zoomRange[0]+1);
            }
            if(mapView.getZoom() > zoomRange[1]){
                mapView.setZoom(zoomRange[1]-1);
            }

        }else{
            // bulgaria
            mapView.setFocusPoint(mapView.getLayers().getBaseLayer().getProjection().fromWgs84(26.483230800000037, 42.550218000000044));
            // zoom - 0 = world, like on most web maps
            mapView.setZoom(5.0f);
            Log.debug("center to default");
        }
    } catch (IOException e) {
        Log.error(e.getMessage());
    }


  // ...
 }

private void copyAssets() {
    AssetManager assetManager = getAssets();
    String[] files = null;
    try {
        files = assetManager.list("");
    } catch (IOException e) {
        Log.error("Failed to get asset file list." + e.getLocalizedMessage());
    }
    for(String filename : files) {
        InputStream in = null;
        OutputStream out = null;
        try {
          in = assetManager.open(filename);
          File outFile = new File(getExternalFilesDir(null), filename);

          if(!outFile.exists()){
              out = new FileOutputStream(outFile);
              copyFile(in, out);
              out.flush();
              out.close();
              out = null;
          }

          in.close();
          in = null;

        } catch(IOException e) {
            Log.error("Failed to copy asset file: " + filename + "\n" + e.getLocalizedMessage());
        }       
    }
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[32 * 1024];
    int read;
    while((read = in.read(buffer)) != -1){
      out.write(buffer, 0, read);
    }
}
JaakL
  • 4,107
  • 5
  • 24
  • 37
  • Do you have set baseLayer? if mbtiles itself is the base layer, not overlay, then use setBaseLayer() instead of addLayer(). I updated my sample above – JaakL May 28 '14 at 07:08
  • I've tried both and it still doesn't work. I've updated my original post with the first 3 lines of my debugger (which contains some errors). – NetworkzZz May 28 '14 at 18:10
  • Make sure you zoom and center map to area what is covered by mbtiles real contents. I added sample code to detect mbtiles area automatically from metadata, but it depends whether metadata is present. The debugger lines are not really relevant here. – JaakL May 29 '14 at 06:17
  • Hello JaakL. Thanks for all the information you gave me, so far it's working perfectly despite the fact I'm having two tiny problems. 1. At times the whole map loads just fine but at times it doesn't load the whole map. 2. When the whole map loads when I try draging the screen to see certain parts of the map the app crashes leaving me with a white screen. – NetworkzZz Jun 02 '14 at 00:28
  • NetworkzZz, can you send a video (with another phone for example) where it happens and your code as app project to nutiteq-dev support https://github.com/nutiteq/hellomap3d/wiki/Support%20and%20discussions, so we can take closer look? From this description can't help much. – JaakL Jun 03 '14 at 05:56
  • Hello JaakL, thanks for your help so far, you've been very patient and helpful. I've done as told, created a thread in the link you sent me. I've also uploaded 2 videos and the whole project in a zip. I posted three dropbox links (I hope you're alright with dropbox), if not please tell me where you want me to upload the files. Thanks once again. – NetworkzZz Jun 05 '14 at 01:37
  • Your mbtiles file has very small map area, and only 2 zoom levels (15 and 16). If you really want to use it, then I suggest to limit datasource accordingly, like this: MBTilesRasterDataSource dataSource = new MBTilesRasterDataSource( new EPSG3857(), 15, 16, getExternalFilesDir(null).getAbsolutePath()+"/newD.mbtiles", false, this); Then there will be no white map when you zoom out or in too much. – JaakL Jun 06 '14 at 14:42
  • ps. Also you probably want to use bigger mbtiles file with more zoom levels and larger area. By the way, there is neat trick how to make mbtiles file much smaller - use webp image format. Only downside is that it requires Android 4.0 as minimum. – JaakL Jun 06 '14 at 14:42
  • Hello JaakL, thanks for your reply. Applying your suggestion I'm finally able to see the whole map with no parts cut. Unfortunately, the map still crashes when I drag it to check certain parts of it. Thanks. – NetworkzZz Jun 07 '14 at 14:49
0

I was also having the same problem.Following links may help you for sure:

https://github.com/nutiteq/hellomap3d/wiki/Offline-map-tiles

how to work on offline 3d maps using nutiteq in android

Please let me know if it works.

Community
  • 1
  • 1
Pihu
  • 1,041
  • 11
  • 35