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!
[sourcecode lang=”java”]
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;
}
}
[/sourcecode]