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

Android ViewModel无法从BackStackEntry获取选中项如何解决

问题根因
  • 你两处获取的MapViewModel作用域不一致,本质是两个完全独立的实例,所以数据无法共享:
    1. ListFragment中使用ViewModelProviders.of(this).get(MapViewModel.class),得到的是和ListFragment自身生命周期绑定的ViewModel实例
    2. MapFragment中使用回退栈条目backStackEntry作为ViewModelStoreOwner,得到的是和fishListFragment回退栈条目绑定的ViewModel实例
      两个实例数据互不相通,自然收不到回调日志。
修复方案

1. 统一ListFragment的ViewModel获取方式

把ListFragment里的ViewModel初始化逻辑改成和MapFragment同作用域,确保拿到的是同一个实例:

// 替换原有的ViewModelProviders.of(this)代码
NavController navController = Navigation.findNavController(requireView());
NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.fishListFragment);
mMapViewModel = new ViewModelProvider(backStackEntry).get(MapViewModel.class);

// 后续点击事件里的select逻辑不变
Log.d("view-click", String.valueOf(fish.getLocation()));
mMapViewModel.select(fish);
Navigation.findNavController(view).navigate(R.id.action_fishListFragment_to_mapFragment2);

修改后两边操作的是同一个ViewModel,你存在里面的Fish数据就能被MapFragment正常接收。

2. 兼容底部导航直接进入MapFragment的场景

如果用户通过底部导航直接进入MapFragment,此时回退栈不存在fishListFragment条目,调用getBackStackEntry会抛出异常,建议加判断做兼容,同时优化观察者的生命周期绑定避免内存泄漏:

NavController navController = NavHostFragment.findNavController(this);
// 先判断是否是从ListFragment跳转过来的
NavBackStackEntry previousEntry = navController.getPreviousBackStackEntry();
if (previousEntry != null && previousEntry.getDestination().getId() == R.id.fishListFragment) {
    NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.fishListFragment);
    mMapViewModel = new ViewModelProvider(backStackEntry).get(MapViewModel.class);
    // 用Fragment的view生命周期作为观察者所有者,避免内存泄漏
    mMapViewModel.getSelected().observe(getViewLifecycleOwner(), fish -> {
        if (fish != null) {
            Log.d("MAPFRAGMENT",fish.getLocation() + "");
            // 处理完后清空选中值,避免回退后再次进入重复触发回调
            mMapViewModel.select(null);
        }
    });
} else {
    // 底部导航直接进入的逻辑,展示默认位置即可
}

3. 可选优化

  • 废弃的ViewModelProviders.of写法可以全部替换成ViewModelProvider构造写法,保持代码风格统一
  • 如果后续还要支持更多页面共享该ViewModel,可以直接把ViewModel的作用域绑定到宿主Activity,就不用处理回退栈的判断逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 20:06:06