1、地址
Github地址:https://gitee.com/mirrors/osmdroid
Git地址:
GitCode - 全球开发者的开源社区,开源代码托管平台
Git下载包地址:Releases · osmdroid/osmdroid · GitHub
- 新建项目
osmdroid在线:
(1)添加依赖
(2)布局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<org.osmdroid.views.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<Button
android:id="@+id/btnLocation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="定位"
android:layout_margin="10dp"
android:layout_alignParentTop="true"/>
</RelativeLayout>
(3)代码MainActivity.java
package com.chy.osmdroid;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.chy.layers.LayerTileSources;
import com.chy.permission.PermissionUtils;
import org.osmdroid.api.IMapController;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.CustomZoomButtonsController;
import org.osmdroid.views.MapView;
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_PERMISSION_CODE = 0;// 权限所用
// 动态申请权限
private String[] permissions = {
Manifest.permission.INTERNET,// 网络权限
Manifest.permission.ACCESS_COARSE_LOCATION,// 精细定位
Manifest.permission.ACCESS_FINE_LOCATION,// 粗定位
Manifest.permission.ACCESS_WIFI_STATE,// 定位权限
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private MapView mapView;
private LocationManager locationManager;// 定位管理器
private Button btnLocation;// 定位按钮
private boolean isLocation = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getPermission();// 获取权限
initControls();
}
/**
* 权限
* */
private void getPermission(){
if (PermissionUtils.hasPermissions(MainActivity.this, permissions)) {
initMap();// 调用初始化地图
} else {
PermissionUtils.requestPermissions(MainActivity.this, REQUEST_PERMISSION_CODE, permissions);
Toast.makeText(getApplicationContext(), "地图加载失败!", Toast.LENGTH_SHORT).show();
}
}
// 地图初始化
private void initMap(){
// 获取mapView实例
mapView = findViewById(R.id.mapView);
// 加载在线地图
mapView.setTileSource(LayerTileSources.AutoNaviVector);
// 设置最小缩放比例
mapView.setMinZoomLevel(3.0);
// 设置最大缩放比例
mapView.setMaxZoomLevel(18.0);
IMapController mapController = mapView.getController();
// 设置地图初始级别
mapController.setZoom(11.0);
// 设置初始中心点
GeoPoint centerPoint = new GeoPoint(43.90, 125.33);
mapController.setCenter(centerPoint);
//启用缩放及滑动手势
//mapView.setBuiltInZoomControls(true);// 废弃得方法,被下面方法所替代
mapView.getZoomController().setVisibility(CustomZoomButtonsController.Visibility.NEVER);
mapView.setMultiTouchControls(true);
}
// 控件初始化
private void initControls(){
btnLocation = findViewById(R.id.btnLocation);
// 点击事件
btnLocation.setOnClickListener(new View.OnClickListener() {
@SuppressLint("MissingPermission")
@Override
public void onClick(View v) {
//创建位置管理器实例
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (!isLocation){
// 注册位置监听器
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
isLocation = !isLocation;
}else {
// 停止位置更新
locationManager.removeUpdates(locationListener);
isLocation = !isLocation;
Toast.makeText(getApplicationContext(),"停止位置更新",Toast.LENGTH_SHORT).show();
}
}
});
}
/**
* 定位监听
* */
LocationListener locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
// 处理位置变化
double latitude = location.getLatitude();
double longitude = location.getLongitude();
Toast.makeText(getApplicationContext(),"lat:"+latitude+"lon:"+longitude,Toast.LENGTH_SHORT).show();
// 在地图上显示当前位置
// ...
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Toast.makeText(getApplicationContext(),"onStatusChanged",Toast.LENGTH_SHORT).show();
}
@Override
public void onProviderEnabled(String provider) {
Toast.makeText(getApplicationContext(),"onProviderEnabled",Toast.LENGTH_SHORT).show();
}
@Override
public void onProviderDisabled(String provider) {
Toast.makeText(getApplicationContext(),"onProviderDisabled",Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onDestroy() {
super.onDestroy();
// 停止位置更新
if (locationManager != null){
locationManager.removeUpdates(locationListener);
}
}
}
(4)代码LayerTileSources.java
package com.chy.layers;
import android.util.Log;
import org.osmdroid.tileprovider.tilesource.OnlineTileSourceBase;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.tileprovider.tilesource.XYTileSource;
import org.osmdroid.util.MapTileIndex;
/**
* 谷歌、高德等瓦片地图
*
* @author jiang zhu on 2019/10/18
*/
public class LayerTileSources extends TileSourceFactory {
//谷歌卫星混合
public static final OnlineTileSourceBase GoogleHybrid = new XYTileSource("Google-Hybrid",
0, 19, 512, ".png", new String[]{
"http://mt0.google.cn",
"http://mt1.google.cn",
"http://mt2.google.cn",
"http://mt3.google.cn",
}) {
@Override
public String getTileURLString(long pMapTileIndex) {
Log.d("url", getBaseUrl() + "/vt/lyrs=y&scale=2&hl=zh-CN&gl=CN&src=app&x=" + MapTileIndex.getX(pMapTileIndex) + "&y=" + MapTileIndex.getY(pMapTileIndex) + "&z=" + MapTileIndex.getZoom(pMapTileIndex));
return getBaseUrl() + "/vt/lyrs=y&scale=2&hl=zh-CN&gl=CN&src=app&x=" + MapTileIndex.getX(pMapTileIndex) + "&y=" + MapTileIndex.getY(pMapTileIndex) + "&z=" + MapTileIndex.getZoom(pMapTileIndex);
}
};
//谷歌卫星
public static final OnlineTileSourceBase GoogleSat = new XYTileSource("Google-Sat",
0, 19, 512, ".png", new String[]{
"http://mt0.google.cn",
"http://mt1.google.cn",
"http://mt2.google.cn",
"http://mt3.google.cn",
}) {
@Override
public String getTileURLString(long pMapTileIndex) {
return getBaseUrl() + "/vt/lyrs=s&scale=2&hl=zh-CN&gl=CN&src=app&x=" + MapTileIndex.getX(pMapTileIndex) + "&y=" + MapTileIndex.getY(pMapTileIndex) + "&z=" + MapTileIndex.getZoom(pMapTileIndex);
}
};
//谷歌地图
public static final OnlineTileSourceBase GoogleRoads = new XYTileSource("Google-Roads",
0, 18, 512, ".png", new String[]{
"http://mt0.google.cn",
"http://mt1.google.cn",
"http://mt2.google.cn",
"http://mt3.google.cn",
}) {
@Override
public String getTileURLString(long pMapTileIndex) {
return getBaseUrl() + "/vt/lyrs=m&scale=2&hl=zh-CN&gl=CN&src=app&x=" + MapTileIndex.getX(pMapTileIndex) + "&y=" + MapTileIndex.getY(pMapTileIndex) + "&z=" + MapTileIndex.getZoom(pMapTileIndex);
}
};
//谷歌地形
public static final OnlineTileSourceBase GoogleTerrain = new XYTileSource("Google-Terrain",
0, 16, 512, ".png", new String[]{
"http://mt0.google.cn",
"http://mt1.google.cn",
"http://mt2.google.cn",
"http://mt3.google.cn",
}) {
@Override
public String getTileURLString(long pMapTileIndex) {
return getBaseUrl() + "/vt/lyrs=t&scale=2&hl=zh-CN&gl=CN&src=app&x=" + MapTileIndex.getX(pMapTileIndex) + "&y=" + MapTileIndex.getY(pMapTileIndex) + "&z=" + MapTileIndex.getZoom(pMapTileIndex);
}
};
//谷歌地形带标注
public static final OnlineTileSourceBase GoogleTerrainHybrid = new XYTileSource("Google-Terrain-Hybrid",
0, 16, 512, ".png", new String[]{
"http://mt0.google.cn",
"http://mt1.google.cn",
"http://mt2.google.cn",
"http://mt3.google.cn",
}) {
@Override
public String getTileURLString(long pMapTileIndex) {
return getBaseUrl() + "/vt/lyrs=p&scale=2&hl=zh-CN&gl=CN&src=app&x=" + MapTileIndex.getX(pMapTileIndex) + "&y=" + MapTileIndex.getY(pMapTileIndex) + "&z=" + MapTileIndex.getZoom(pMapTileIndex);
}
};
//高德地图
public static final OnlineTileSourceBase AutoNaviVector = new XYTileSource("AutoNavi-Vector",
0, 20, 256, ".png", new String[]{
"https://wprd01.is.autonavi.com/appmaptile?",
"https://wprd02.is.autonavi.com/appmaptile?",
"https://wprd03.is.autonavi.com/appmaptile?",
"https://wprd04.is.autonavi.com/appmaptile?",
}) {
@Override
public String getTileURLString(long pMapTileIndex) {
return getBaseUrl() + "x=" + MapTileIndex.getX(pMapTileIndex) + "&y=" + MapTileIndex.getY(pMapTileIndex) + "&z="
+ MapTileIndex.getZoom(pMapTileIndex) + "&lang=zh_cn&size=1&scl=1&style=7<ype=7";
}
};
}
(5)权限代码
AndroidManifest.xml权限代码
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
PermissionUtils.java 代码
package com.chy.permission;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import androidx.annotation.NonNull;
import androidx.annotation.Size;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.List;
/**
* 动态申请权限工具类
* Created by xiaoyehai on 2018/4/25 0025.
*/
public class PermissionUtils {
public static final int GOTO_SEETING_CODE = 152;
/**
* 判断是否有权限
*
* @param context
* @param perms
* @return
*/
public static boolean hasPermissions(@NonNull Context context, @Size(min = 1) @NonNull String... perms) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
if (context == null) {
throw new IllegalArgumentException("Can't check permissions for null context");
}
for (String perm : perms) {
if (ContextCompat.checkSelfPermission(context, perm) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
/**
* 申请权限
*/
public static void requestPermissions(@NonNull Activity activity, int requestCode, String[] permissions) {
List<String> permissionList = new ArrayList<>();
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(permission);
}
}
String[] permissionsArray = permissionList.toArray(new String[permissionList.size()]);//将List转为数组
if (permissionList.isEmpty()) {
//不可能为空
} else {
ActivityCompat.requestPermissions(activity, permissionsArray, requestCode);
//返回结果onRequestPermissionsResult
}
}
/**
* 申请权限的回调
*
* @param requestCode 请求权限时传入的请求码,用于区别是哪一次请求的
* @param permissions 所请求的所有权限的数组
* @param grantResults 权限授予结果,和 permissions 数组参数中的权限一一对应,元素值为两种情况,如下:
* 授予: PackageManager.PERMISSION_GRANTED
* 拒绝: PackageManager.PERMISSION_DENIED
*/
public static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults, @NonNull PermissionCallbacks callBack) {
//授予的权限。
List<String> granted = new ArrayList<>();
//拒绝的权限
List<String> denied = new ArrayList<>();
for (int i = 0; i < permissions.length; i++) {
String perm = permissions[i];
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
granted.add(perm);
} else {
denied.add(perm);
}
}
if (null != callBack) {
if (denied.isEmpty()) {
callBack.onPermissionsAllGranted(requestCode, granted, denied.isEmpty());
}
if (!denied.isEmpty()) {
callBack.onPermissionsDenied(requestCode, denied);
}
}
}
/**
* 用户是否拒绝权限,并检查“不要提醒”。
*
* @param activity
* @param perms
* @return
*/
public static boolean somePermissionPermanentlyDenied(Activity activity, @NonNull List<String> perms) {
for (String deniedPermission : perms) {
if (permissionPermanentlyDenied(activity, deniedPermission)) {
return true;
}
}
return false;
}
public static boolean permissionPermanentlyDenied(Activity activity, @NonNull String perms) {
if (!ActivityCompat.shouldShowRequestPermissionRationale(activity, perms)) {
return true;
}
return false;
}
public static void showDialogGoToAppSettting(final Activity activity) {
AlertDialog dialog = new AlertDialog.Builder(activity)
.setMessage("去设置界面开启权限")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// 跳转到应用设置界面
goToAppSetting(activity);
}
}).setCancelable(false).show();
}
/**
* 跳转到应用设置界面
*/
public static void goToAppSetting(Activity activity) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
intent.setData(uri);
activity.startActivityForResult(intent, GOTO_SEETING_CODE);
}
public static void showPermissionReason(final int requestCode, final Activity activity, final String[] permission, String s) {
AlertDialog dialog = new AlertDialog.Builder(activity)
.setMessage(s)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
requestPermissions(activity, requestCode, permission);
}
})
.setCancelable(false).show();
}
public interface PermissionCallbacks {
/**
* @param isAllGranted 是否全部同意
*/
void onPermissionsAllGranted(int requestCode, List<String> perms, boolean isAllGranted);
/**
*/
void onPermissionsDenied(int requestCode, List<String> perms);
}
}
(6)加载离线地图
// 加载离线地图OSMDroid支持多种地图文件格式,如MBTiles、SQLiteDatabase、ZIP文件等
String strFilepath = Environment.getExternalStorageDirectory().getPath() +
"/osmdroid/xian.mbtiles"; // 在 此处替换自己的资源
File exitFile = new File(strFilepath);
String fileName = "xian.mbtiles";
if (!exitFile.exists() && !fileName.contains(".")) {
mapView.setTileSource(org.osmdroid.tileprovider.tilesource.TileSourceFactory.MAPNIK);
} else {
fileName = fileName.substring(fileName.lastIndexOf(".") + 1);
if (fileName.length() == 0)
return;
/**
*
* extensionMap.put("zip", ZipFileArchive.class);
if(VERSION.SDK_INT >= 10) {
extensionMap.put("sqlite", DatabaseFileArchive.class);
extensionMap.put("mbtiles", MBTilesFileArchive.class);
extensionMap.put("gemf", GEMFFileArchive.class);
}
这里加载上面四种地图格式
*/
if (ArchiveFileFactory.isFileExtensionRegistered(fileName)) {
try {
OfflineTileProvider tileProvider = new OfflineTileProvider(new
SimpleRegisterReceiver(getApplicationContext()),
new File[]{exitFile});
mapView.setTileProvider(tileProvider);
String source = "";
IArchiveFile[] archives = tileProvider.getArchives();
if (archives.length > 0) {
Set<String> tileSources = archives[0].getTileSources();
if (!tileSources.isEmpty()) {
source = tileSources.iterator().next();
mapView.setTileSource(FileBasedTileSource.getSource(source));
} else {
mapView.setTileSource(org.osmdroid.tileprovider.tilesource
.TileSourceFactory.DEFAULT_TILE_SOURCE);
}
} else
mapView.setTileSource(org.osmdroid.tileprovider.tilesource
.TileSourceFactory.DEFAULT_TILE_SOURCE);
} catch (Exception ex) {
ex.printStackTrace();
}
}