Integrating osmdroid part 2 – Using MBTiles as offline data source

Yesterday I wrote an article about how to integrate the osmdroid library into an Eclipse project. You may have noticed I didn’t mention anything about actually creating an Activity that actually does something with the freshly installed library.

Let’s change that :-). Below you’ll find a¬†heavily¬†commented example on how to instantiate a MapView using an offline MBTiles map source. Since creating an mbtiles file is also a project on its own, I’ll see if I can write something up about that process soon.

Questions? Let me know!

package com.example.yourproject;

import java.io.File;

import org.osmdroid.DefaultResourceProxyImpl;
import org.osmdroid.ResourceProxy;
import org.osmdroid.tileprovider.MapTileProviderArray;
import org.osmdroid.tileprovider.modules.IArchiveFile;
import org.osmdroid.tileprovider.modules.MBTilesFileArchive;
import org.osmdroid.tileprovider.modules.MapTileFileArchiveProvider;
import org.osmdroid.tileprovider.modules.MapTileModuleProviderBase;
import org.osmdroid.tileprovider.tilesource.XYTileSource;
import org.osmdroid.tileprovider.util.SimpleRegisterReceiver;
import org.osmdroid.views.MapController;
import org.osmdroid.views.MapView;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.Menu;

public class RouteMapActivity extends Activity {

  @SuppressWarnings("unused")
  private static final String TAG = "RouteMapActivity";

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    /**
    * This whole thing revolves around instantiating a MapView class, way,
    * way below. And MapView requires a ResourceProxy. Who are we to deny
    * its needs? Let's create one!
    *
    * It would have been nice if this was taken care of in the MapView
    * constructor. Interestingly MapView *has* a constructor that creates a
    * new DefaultResourceProxyImpl but unfortunately that one doesn't allow
    * us to specify the parameters we *do* need to set ...
    */
    DefaultResourceProxyImpl resProxy;
    resProxy = new DefaultResourceProxyImpl(this.getApplicationContext());

    /**
    * A class that implements the ITileSource interface knows how to
    * convert an InputStream or a file path into a Drawable. It doesn't do
    * much more than that. The real 'sourcery' is performed by
    * MapTileFileArchiveProvider which will be introduced shortly.
    *
    * What we need is really a BitmapTileSourceBase instance, but this
    * class is defined as abstract. XYTileSource is not and comes closest
    * to what we want.
    *
    * Comment: I don't quite get why BitmapTileSource base is abstract; it
    * doesn't contain any abstract methods.
    */
    XYTileSource tSource;
    tSource = new XYTileSource("mbtiles",
    ResourceProxy.string.offline_mode,
    8, 15, 256, ".png", "http://who.cares/");

    /**
    * Don't think the name SimpleRegisterReceiver is particularly well
    * chosen. SimpleReceiverRegistrar would have been better because the
    * only thing SimpleRegisterReceiver does, is wrap the methods
    * Context.registerReceiver(..) and Context.unregisterReceiver(..). Have
    * a look at the source if you don't believe me ;-).
    *
    * So why does it exist then?? Don't know, but it's quite possible to
    * just ignore this step and state the Activity implements
    * IRegisterReceiver and replace the 'simpleReceiver' variable with
    * 'this' further down (no additional implementation required).
    */
    SimpleRegisterReceiver sr = new SimpleRegisterReceiver(this);

    /**
    * The following looks complicated, but really only creates an
    * iArchiveFile[]. Apparently Marc Kurtz and Nicolas Gramlich, the
    * authors of MapTileFileArchiveProvider, figured it might be useful to
    * support multiple files/sources. I guess that might make sense if
    * you're providing separate files for, for example, cities.
    *
    * They also provided quite a bit of logic in MapTileFileArchiveProvider
    * for handling SD Card inserts and ejects. Additionally, if files are
    * not explicitly specified they can be dynamically loaded from the
    * /mnt/sdcard/osmdroid directory, which is a nice feature.
    */
    String packageDir = "/com.example.yourproject";
    String p = Environment.getExternalStorageDirectory() + packageDir;
    File f = new File(p, "TileDatabase.mbtiles");
    IArchiveFile[] files = { MBTilesFileArchive.getDatabaseFileArchive(f) };

    MapTileModuleProviderBase moduleProvider;
    moduleProvider = new MapTileFileArchiveProvider(sr, tSource, files);

    /**
    * So at this point we have a MapTileModuleProvider that provides
    * MapTileModules: a MapTileModule looks at one or more sources, which
    * are *not* ITileSources but IArchiveFiles and provides MapTiles. What,
    * then, does MapTileProviderArray do? Well, it just adds another layer
    * to the complexity cake: this makes it possible to set multiple
    * MapTileModuleProviders, such as an on- and offline source. I'm sure
    * it's useful for someone, but for simple applications it's probably
    * too much.
    */
    MapTileModuleProviderBase[] pBaseArray;
    pBaseArray = new MapTileModuleProviderBase[] { moduleProvider };

    MapTileProviderArray provider;
    provider = new MapTileProviderArray(tSource, null, pBaseArray);

    /**
    * Are we there yet??? Create the MapView already!
    */
    MapView mapView = new MapView(this, 256, resProxy, provider);
    mapView.setBuiltInZoomControls(true);

    // Zoom in and go to Amsterdam
    MapController controller = mapView.getController();
    controller.setZoom(12);
    controller.animateTo(new LatLonPoint(52.373444, 4.892229));

    // Set the MapView as the root View for this Activity; done!
    setContentView(mapView);

  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_route_map, menu);
    return true;
  }

}
Tagged , . Bookmark the permalink.

4 Responses to Integrating osmdroid part 2 – Using MBTiles as offline data source

  1. Peter says:

    Hi what kind of link should i put inside the tileSource to make it work with MapBox ?

    (instead of the http://who.cares/)

    the link looks like this : “http://a.tiles.mapbox.com/v3/myusername.map-f1rhoycw/page.html#3.00/0.00/0.00″

  2. felixonca says:

    Very helpful, thanks.

  3. Patrick says:

    Hi there.
    Lines controller.animateTo(new LatLonPoint(52.373444, 4.892229)); and
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_route_map, menu);
    return true;
    }

    Give me errors. Some ideas? Thank you very much!!

Leave a Reply to felixonca Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>