You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

osmdroid地图Fragment切换后显示灰色瓦片,日志报TileLoader failed to load tile due to mWriter being null

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.20 10:30:30