osmdroid地图Fragment切换后显示灰色瓦片,日志报TileLoader failed to load tile due to mWriter being null
我太懂这种头疼的感觉了——Fragment切来切去后地图直接变成一片灰,还弹出TileLoader failed to load tile due to mWriter being null的报错,试了好几种方法都没效果对吧?结合osmdroid的生命周期特性,我给你几个针对性的解决方案,你可以挨个试试:
1. 严格绑定Fragment与MapView的全生命周期
你之前试过在onPause/onResume调用地图的对应方法,但可能没覆盖完整的生命周期环节。osmdroid的MapView对生命周期的依赖很强,必须在Fragment的每个生命周期节点都做对应处理,尤其是onDestroyView阶段:
private MapView mapView; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_map, container, false); mapView = view.findViewById(R.id.mapView); mapView.onCreate(savedInstanceState); // 基础配置要在这里初始化 Configuration.getInstance().setUserAgentValue(requireContext().getPackageName()); mapView.setTileSource(TileSourceFactory.MAPNIK); mapView.getController().setZoom(17); return view; } @Override public void onStart() { super.onStart(); mapView.onStart(); } @Override public void onResume() { super.onResume(); mapView.onResume(); } @Override public void onPause() { super.onPause(); mapView.onPause(); } @Override public void onStop() { super.onStop(); mapView.onStop(); } @Override public void onDestroyView() { super.onDestroyView(); mapView.onDestroy(); mapView = null; // 关键!避免持有过期引用导致生命周期混乱 } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); mapView.onSaveInstanceState(outState); }
2. 重置TileProvider强制刷新瓦片
报错里的mWriter being null大概率是TileWriter被提前销毁,但地图还在尝试加载瓦片。可以在Fragment回到前台时,强制清空缓存并重置TileProvider:
@Override public void onResume() { super.onResume(); mapView.onResume(); // 强制刷新瓦片源 if (mapView.getTileProvider() != null) { mapView.getTileProvider().clearTileCache(); mapView.setTileSource(mapView.getTileSource()); // 触发重新加载 } }
3. 换用Fragment的hide/show切换方式
如果之前用的是replace方法切换Fragment,每次切换都会销毁第一个Fragment的View再重建,很容易打乱MapView的生命周期。试试用hide/show来切换,保留Fragment的View实例:
// 切换Fragment时的代码示例 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); if (mapFragment.isAdded()) { transaction.hide(otherFragment).show(mapFragment); } else { transaction.add(R.id.container, mapFragment); } transaction.commit();
4. 检查瓦片源的网络权限配置
你之前加的network_security_config.xml只包含了openptmap.org,但如果用的是默认的MAPNIK瓦片源,它的域名是tile.openstreetmap.org,没加这个的话肯定访问不到瓦片!修改配置:
<network-security-config> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">tile.openstreetmap.org</domain> <domain includeSubdomains="true">openptmap.org</domain> <!-- 其他你用到的瓦片源域名都要加上 --> </domain-config> </network-security-config>
同时别忘了Manifest里的基础权限:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
建议你先检查第4点的网络配置,很多时候灰色瓦片都是因为访问不到瓦片服务器;然后再调整生命周期绑定逻辑,这是osmdroid在Fragment中最容易踩的坑。如果还是不行,试试用hide/show的方式切换Fragment,避免View频繁销毁重建。
备注:内容来源于stack exchange,提问作者GABRIEL MONCZEWSKI

