osmdroid高级教程

The best example of how to use the osmdroid library is our OpenStreetMapViewer sample project. It contains a basic osmdroid application plus a few special-use examples. It is recommended you use this project as an example for building your application.

学习如何使用osmdroid类库的最好的例子就是我们的OpenStreetMapViewer样例项目。它包含了一个基本的osmdroid应用外加几个特殊用途的例子。建议你使用该项目作为创建你自己应用的例子。

Adding a MapView(这个onCreateView只能放到Fragment类的继承类里吗?)

You can add a MapView to your xml layout using:

你可以使用如下代码添加一个MapView到你的xml layout:

<org.osmdroid.views.MapView
    android:id="@+id/mapview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tilesource="Mapnik" />

This will allow you to configure the tile source imagery for your MapView but not much else.

这将允许你为你的MapView配置切片数据源图像,但是没有太多其它的。

However, for more control over your MapView, you will want to create a MapView programmatically.

但是,要在你的MapView上添加更多的控制,你将想要通过编程的方式创建一个MapView。

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    mMapView = new MapView(inflater.getContext(), 256, getContext());
    return mMapView;
}

Images for Buttons and whatnot

For osmdroid 4.3 and older, there's a number of resources that the map uses for various user interface helpers, such as zoom in/out buttons, the device's current location when GPS is available and more. These resources are loaded via the "ResourceProxy". The idea is that you can either bring your own images or borrow the ones from osmdroid. If you're borrowing, then you'll want to grab the files located here and add them to your project "src/main/res/drawable".

对于osmdroid4.3及更高版本,地图有许多资源可用于各种用户界面帮助程序,例如放大/缩小按钮、GPS可用时设备的当前位置等等。这些资源是通过“ResourceProxy”加载的。这个想法是你可以带上你自己的图像或者从osmdroid借用那些图像。如果您正在借用,那么您需要获取位于此处的文件,并将它们添加到您的项目“src/main/res/drawable”中。

For osmdroid 5.0 and 5.1, the drawables are included with the AAR package. The resource proxy is still present and used so you can override values and images as needed.

对于osmdroid 5.0和5.1,AAR软件包中包含可提取的内容。资源代理仍然存在并使用,因此您可以根据需要覆盖值和图像。

For osmdroid 5.2 and up, the resource proxy is removed from the API set and replaced with Android context.

对于osmdroid5.2及更高版本,资源代理将从API集中移除,并替换为Android上下文。

Create a custom Resource Proxy创建一个自定义的资源代理

Applies only to versions prior to 5.2只应用于5.2之前的版本

As mentioned above, the Resource Proxy is a bit of a strange animal that osmdroid uses to load some images for user interface controls. If you're using any of the built-in controls that need images (zoom in/out, person icon, etc) you'll either need to provide your own images, borrow the images from osmdroid's example app, or provide your own implementation of Resource Proxy.

如上所述,资源代理是一种奇怪的动物,osmdroid使用它来为用户界面控件加载一些图像。如果您正在使用任何需要图像(放大/缩小、人物图标等)的内置控件,则需要提供自己的图像、借用osmdroid示例应用程序中的图像或提供自己的资源代理实现。

The example osmdroid app includes an example of this called CustomResourceProxy (included with > 4.3 osmdroid). All it does is change the my location drawable (person) to an alternate image. The example is below.

示例osmdroid应用程序包括一个名为CustomResourceProxy的示例(包含在>4.3 osmdroid中)。它所做的只是改变我的位置绘制(人)到另一个形象。示例如下。

public class CustomResourceProxy extends DefaultResourceProxyImpl {

     private final Context mContext;
     public CustomResourceProxy(Context pContext) {
          super(pContext);
		mContext = pContext;
     }
     
     @Override
	public Bitmap getBitmap(final bitmap pResId) {
		switch (pResId){
               case person:
                    //your image goes here!!!
                    return BitmapFactory.decodeResource(mContext.getResources(),org.osmdroid.example.R.drawable.sfgpuci);
          }
          return super.getBitmap(pResId);
	}

	@Override
	public Drawable getDrawable(final bitmap pResId) {
		switch (pResId){
               case person:
                    return mContext.getResources().getDrawable(org.osmdroid.example.R.drawable.sfgpuci);
          }
          return super.getDrawable(pResId);
	}
}

Then you can use your instance using the following snippet.

mResourceProxy = new CustomResourceProxy(getApplicationContext());
final RelativeLayout rl = new RelativeLayout(this);
this.mOsmv = new MapView(this,mResourceProxy);

In order to see any difference with our example (changes the person icon), we'll need to get a location fix and add it to the map layers.

this.mLocationOverlay = new MyLocationNewOverlay(new GpsMyLocationProvider(this), mOsmv, mResourceProxy);
this.mLocationOverlay.enableMyLocation();
this.mOsmv.getOverlays().add(mLocationOverlay);
this.mOsmv.setMultiTouchControls(true);

Map Overlays

How to add the My Location overlay

Note: you need manifest Fine Location permissions and if you are targeting API23+ APIs, you have to ask the user to explicitly grant location runtime permissions.

Notice: this is a very simple example that does not handle android lifecycle correctly. Versions 5.6.5 and older, you'll need to handle automatically disabling/enabling the location provider with android life cycle events. Version 6.0.0, this is handled so long as you call map view onPause and onResume appropriately.

this.mLocationOverlay = new MyLocationNewOverlay(new GpsMyLocationProvider(context),mMapView);
this.mLocationOverlay.enableMyLocation();
mMapView.getOverlays().add(this.mLocationOverlay);

How to add a compass overlay

Notice: this is a very simple example that does not handle android lifecycle correctly. Versions 5.6.5 and older, you'll need to handle automatically disabling/enabling the compass/orientation provider with android life cycle events. Version 6.0.0, this is handled so long as you call map view onPause and onResume appropriately.

this.mCompassOverlay = new CompassOverlay(context, new InternalCompassOrientationProvider(context), mMapView);
this.mCompassOverlay.enableCompass();
mMapView.getOverlays().add(this.mCompassOverlay);

How to enable the Grid line Overlay

Useful for displaying latitude/longitude grid lines.

v5.2 up to v5.6.5, see the sample app's source code from those tagged versions.

v6.0.0 and up

LatLonGridlineOverlay2 overlay = new LatLonGridlineOverlay2();
mMapView.getOverlays().add(overlay);

How to enable rotation gestures

mRotationGestureOverlay = new RotationGestureOverlay(context, mMapView);
mRotationGestureOverlay.setEnabled(true);
mMapView.setMultiTouchControls(true);
mMapView.getOverlays().add(this.mRotationGestureOverlay);

How to add Map Scale bar overlay

final Context context = this.getActivity();
final DisplayMetrics dm = context.getResources().getDisplayMetrics();
mScaleBarOverlay = new ScaleBarOverlay(mMapView);
mScaleBarOverlay.setCentred(true);
//play around with these values to get the location on screen in the right place for your application
mScaleBarOverlay.setScaleBarOffset(dm.widthPixels / 2, 10);
mMapView.getOverlays().add(this.mScaleBarOverlay);

How to add the built-in Minimap

Note: do not use when rotation is enabled! (Keep reading for a work around)

mMinimapOverlay = new MinimapOverlay(context, mMapView.getTileRequestCompleteHandler());
mMinimapOverlay.setWidth(dm.widthPixels / 5);
mMinimapOverlay.setHeight(dm.heightPixels / 5);
//optionally, you can set the minimap to a different tile source
//mMinimapOverlay.setTileSource(....);
mMapView.getOverlays().add(this.mMinimapOverlay);

Versions 5.6.5 and older: If you want the minimap to stay put when rotation is enabled, create a second map view in your layout file, then wire up a change listener on the main map and use that to set the location on the minimap. For the reverse, you need to do the same process, however, you have to filter map motion events to prevent infinite looping. There's an example on how to sync the views within the example application.

Version 6.0.0: the above tip is no longer necessary.

How do I place icons on the map with a click listener?

//your items
ArrayList<OverlayItem> items = new ArrayList<OverlayItem>();
items.add(new OverlayItem("Title", "Description", new GeoPoint(0.0d,0.0d))); // Lat/Lon decimal degrees

//the overlay
ItemizedOverlayWithFocus<OverlayItem> mOverlay = new ItemizedOverlayWithFocus<OverlayItem>(items,
	new ItemizedIconOverlay.OnItemGestureListener<OverlayItem>() {
	@Override
	public boolean onItemSingleTapUp(final int index, final OverlayItem item) {
	//do something
	    return true;
	}
	@Override
	public boolean onItemLongPress(final int index, final OverlayItem item) {
		return false;
	}
}, context);
mOverlay.setFocusItemsOnTap(true);

mMapView.getOverlays().add(mOverlay);

How many icons can I put on the map?

The answer is greatly dependent on what hardware the osmdroid based app is running on. A Samsung S5 (no endorsement intended) ran just fine at 3k icons and was noticeably choppy at 6k icons. Your mileage may vary. X86 Android running on modern hardware will perform great at even higher numbers. However, it's recommended to limit the amount of stuff you're rendering, if at all possible.

If you're also drawing paths, lines, polygons, etc, then this also changes the equation. Drawing multipoint graphics is computationally more expensive and thus negatively affects performance under higher loads. To mitigate performance issues with multipoint graphics, one strategy would be to reduce the number of points handed off to the map engine when at a higher zoom level (numerically lower), then increase the fidelity as the user zoom's in. In effect, you would be clipping the visible data at the map view bounds so that the map view only "knows" about what's on screen and doesn't have to loop through all 10k icons that you want on the map. Although you can give the map view all 10k objects, but every time the map moves or zooms, it will iterate over all 10k items to calculate where to draw them (if at all). Using this mechanism paired with map motion listeners and a database query that supports geographic bounds, you can support a rich experience for users with lots of data and still have reasonable performance.

Reusing drawables for icons will help with memory usage too.

Map Sources, Imagery and Tile sets.

See https://github.com/osmdroid/osmdroid/wiki/Map-Sources

Using osmdroid in a recycler view

Applies to: v5.6.5 and older. (v6.0.0 has this fix applied already)

It has been brought up a view times that osmdroid's MapView does not play nicely in a RecyclerView. The MapView is a custom android ViewGroup that implements the necessary API calls that ViewGroup requires, namely onDetachedFromWindow. In this function call, osmdroid basically calls destructors on all associated overlays, threading, tile loading, etc. This is destructive and cannot be reinitialized. This was done primarily to prevent memory leaks. Since ViewGroup does not have a destroy method or anything else that happens during garbage collection, this is really the only place we can put clean up code. As such, using the map in a recycler view won't work without this simple one liner.

    if (Build.VERSION.SDK_INT >= 16)
	mapView.setHasTransientState(true);

Now naturally, this will only function on devices at API16 (Jelly Bean) and newer so the recommendation is to simply not use osmdroid in a recycler view for older APIs. The alternative approach is for you to extend the MapView and override the method for public void onDetach() and simply provide an empty body. This will create memory leaks though so use with caution.

Related tickets:

原文地址:https://www.cnblogs.com/2008nmj/p/14957908.html