Search code examples
androidnutiteqmbtiles

Importing .mbfiles extension files for Android with Nutiteq


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

Solution

  • 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);
        }
    }