咨询:osmdroid地图仅显空白网格,无外部存储权限如何解决?
解决osmdroid空白网格+无需外部存储权限的问题
嘿,我看了你遇到的问题——osmdroid只显示空白网格,而且设备不支持外部存储,想去掉SD卡权限对吧?咱们一步步来解决:
一、先搞定「无需外部存储权限」的配置
osmdroid确实默认会依赖外部存储,但完全可以把缓存路径移到应用内部存储,这样就不需要READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限了。
1. 修改Manifest权限
直接删掉这两个冗余权限:
<!-- 移除这两行权限声明 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
如果你的目标SDK是Android 10+,系统会因为Scoped Storage特性自动忽略这类权限请求,放心删掉就行。
2. 正确配置内部存储缓存路径
你代码里已经尝试设置缓存路径,但存在重复初始化Configuration的问题,顺序也有点混乱。正确的做法是:在初始化mapView之前,一次性完成Configuration配置,不要重复调用load方法。
修改后的初始化代码示例:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 第一步:优先配置osmdroid缓存到内部存储 Context appContext = getApplicationContext(); Configuration config = Configuration.getInstance(); // 用应用专属的内部缓存目录(getCacheDir),无需权限 File basePath = new File(getCacheDir(), "osmdroid"); File tileCache = new File(basePath, "tiles"); // 确保目录存在,避免初始化失败 if (!tileCache.exists()) { tileCache.mkdirs(); } config.setOsmdroidBasePath(basePath); config.setOsmdroidTileCache(tileCache); // 必须设置用户代理,否则多数瓦片服务器会拒绝请求 config.setUserAgentValue(BuildConfig.APPLICATION_ID); // 仅加载一次配置 config.load(appContext, PreferenceManager.getDefaultSharedPreferences(appContext)); // 第二步:再初始化布局和mapView setContentView(R.layout.activity_directmap); ButterKnife.bind(this); mapView = findViewById(R.id.mapViewosm); mapView.setMultiTouchControls(true); mapView.setBuiltInZoomControls(true); // 以下是你的业务逻辑代码 roadManager = new GraphHopperRoadManager(getString(R.string.apikey), true); manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); route.setOnClickListener(this); startIcon = BitmapFactory.decodeResource(appContext.getResources(), R.drawable.ic_mark); lat = -5.402213; lng = 105.264113; setupOverlay(); setupMap(); addMarker(); }
二、解决空白网格的核心问题
你代码里有几个可能导致空白的细节问题,咱们逐个修正:
1. 避免重复设置TileSource
你在onCreate里先设置了MAPNIK瓦片源,又在setupMap里改成Bing源,这种重复操作可能导致初始化异常。建议统一在setupMap里配置瓦片源,同时确保API Key有效:
private void setupMap() { // 确认Bing Key是有效且绑定了正确包名的 BingMapTileSource.setBingKey(getString(R.string.bingkey)); BingMapTileSource bingMap = new BingMapTileSource(null); bingMap.setStyle(BingMapTileSource.IMAGERYSET_ROAD); // 添加覆盖层 mapView.getOverlays().add(rotationGestureOverlay); mapView.getOverlays().add(compassOverlay); mapView.getOverlays().add(myLocationNewOverlay); mapView.getOverlays().add(roadNodeMarkers); // 统一设置瓦片源 mapView.setTileSource(bingMap); mapView.setTilesScaledToDpi(true); mapView.setMinZoomLevel(1.0); mapView.setMaxZoomLevel(21.0); mapView.setMultiTouchControls(true); mapView.setUseDataConnection(true); mapView.getZoomController().setVisibility(CustomZoomButtonsController.Visibility.NEVER); // 确保mapView初始化完成后再获取控制器 IMapController mapController = mapView.getController(); mapController.setZoom(15); // 先设置合理缩放级别,再移动位置 mapController.animateTo(new GeoPoint(-5.402213, 105.264093)); // 最后强制刷新地图 mapView.invalidate(); }
2. 确保用户代理(User-Agent)正确设置
很多瓦片服务器(比如OSM、Bing)会拒绝无User-Agent的请求,所以config.setUserAgentValue(BuildConfig.APPLICATION_ID)必须放在初始化最前面,且只设置一次。
3. 排查网络与瓦片源有效性
- 确认设备网络正常,无代理/防火墙阻挡瓦片请求;
- 如果Bing瓦片仍无法加载,可以临时切换到OSM默认源测试:
mapView.setTileSource(TileSourceFactory.MAPNIK),如果OSM能显示,说明是Bing API Key的问题,需要检查Key的有效性。
三、额外调试技巧
可以打开Logcat搜索osmdroid关键词,查看是否有瓦片加载失败的错误日志,这能帮你快速定位具体问题(比如网络错误、权限问题、路径不存在等)。
内容的提问来源于stack exchange,提问作者Ewa Saputra
相关产品推荐
相关产品推荐

