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

使用Android Navigation Component如何避免点击底部导航时地图页刷新

问题核心原因

Jetpack Navigation 组件默认的底部导航绑定逻辑,切换页签时会销毁前一个页签的Fragment实例,下次切回时会重新执行onCreateView、onViewCreated生命周期,所以地图会被重新加载。

适配现有NavGraph的解决方案

你当前已经拆分了三个子导航图,最合适的方案是多NavHostFragment独立存储+hide/show切换,无需修改现有子页面导航逻辑,也能保留每个页签的独立回退栈,同时避免地图页重建:

1. 修改主页布局

把activity_main.xml中原先的单个NavHostFragment替换为普通的Fragment容器:

<FrameLayout
    android:id="@+id/nav_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />

<com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/bottomNavigationView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    app:menu="@menu/bottom_nav_menu" />

2. 初始化三个独立的NavHostFragment

在MainActivity的onCreate中提前初始化三个导航图对应的NavHostFragment,全部添加到容器后默认显示首页导航:

// 全局变量
private NavHostFragment currentNavHost;
private NavHostFragment homeNavHost;
private NavHostFragment dashboardNavHost;
private NavHostFragment menuNavHost;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView);

    // 初始化三个导航宿主
    homeNavHost = NavHostFragment.create(R.navigation.home);
    dashboardNavHost = NavHostFragment.create(R.navigation.dashboard);
    menuNavHost = NavHostFragment.create(R.navigation.menu);

    // 全部添加到容器,默认显示首页,隐藏其他
    getSupportFragmentManager().beginTransaction()
            .add(R.id.nav_container, homeNavHost, "home")
            .add(R.id.nav_container, dashboardNavHost, "dashboard")
            .hide(dashboardNavHost)
            .add(R.id.nav_container, menuNavHost, "menu")
            .hide(menuNavHost)
            .commit();
    currentNavHost = homeNavHost;

    // 绑定ActionBar到当前显示的导航宿主
    setupActionBarWithNavController(this, currentNavHost.getNavController());
}

3. 重写底部导航切换逻辑

切换时仅做hide和show操作,不会销毁任何NavHost实例,对应页签下的Fragment栈完全保留:

bottomNavigationView.setOnItemSelectedListener(item -> {
    NavHostFragment targetNavHost = null;
    if (item.getItemId() == R.id.home) {
        targetNavHost = homeNavHost;
    } else if (item.getItemId() == R.id.dashboard) {
        targetNavHost = dashboardNavHost;
    } else if (item.getItemId() == R.id.menu) {
        targetNavHost = menuNavHost;
    }
    if (targetNavHost == null || targetNavHost == currentNavHost) {
        return false;
    }
    // 切换导航宿主
    getSupportFragmentManager().beginTransaction()
            .hide(currentNavHost)
            .show(targetNavHost)
            .commit();
    currentNavHost = targetNavHost;
    // 更新ActionBar绑定
    setupActionBarWithNavController(this, currentNavHost.getNavController());
    return true;
});

4. 地图页额外缓存优化

在HomeFragment中增加View缓存,避免即使宿主不销毁,也不会重复inflate布局:

public class HomeFragment extends Fragment {
    private View rootView;
    private SupportMapFragment mapFragment;
    private GoogleMap googleMap;

    private OnMapReadyCallback callback = new OnMapReadyCallback() {
        @Override
        public void onMapReady(GoogleMap map) {
            googleMap = map;
            LatLng sydney = new LatLng(-34, 151);
            googleMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
            googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
        }
    };

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater,
                             @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        // 已初始化过View直接返回,避免重复加载
        if (rootView != null) {
            // 移除原有父布局绑定,避免重复添加报错
            if (rootView.getParent() != null) {
                ((ViewGroup) rootView.getParent()).removeView(rootView);
            }
            return rootView;
        }
        rootView = inflater.inflate(R.layout.fragment_home, container, false);
        return rootView;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        // 地图已初始化过直接跳过
        if (googleMap != null) {
            return;
        }
        super.onViewCreated(view, savedInstanceState);
        mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
        if (mapFragment != null) {
            mapFragment.getMapAsync(callback);
        }
    }
}

原有Transaction方案修复

你之前的Transaction方案问题出在每次切换都执行remove操作,把Fragment实例销毁了,把remove换成hide、add操作换成仅第一次添加,后续切换仅做hide和show,也能实现不销毁地图页的效果。


内容的提问来源于stack exchange,提问作者Jessica Katerina

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 13:18:03