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

切换NavigationView后ViewPager2的Fragment空指针崩溃问题求解

问题分析与解决方案

崩溃原因

报错显示BoxAdapter.notifyDataSetChanged()调用时出现空指针,核心原因有两点:

  1. ViewPager2的FragmentStateAdapter会在Fragment离屏(切换到其他页面)时销毁其视图,此时OneFragment的adapter变量会因视图销毁失去有效引用;若返回HomeFragment后,OneFragment未被重新加载视图(比如ViewPager2当前显示的是TwoFragment),adapter会保持未初始化的null状态。
  2. HomeFragment直接持有OneFragment的实例引用,当ViewPager2重建Fragment时,该引用可能指向未初始化视图的旧实例,调用clearBox()时触发空指针。

解决方案

方案1:增加空值判断,避免直接调用null对象

修改OneFragment的clearBox()方法,先校验关键变量的有效性,同时在视图销毁时清理引用避免内存泄漏:

public void clearBox() {
    // 先判断boxList和adapter是否有效
    if (boxList != null && adapter != null) {
        boxList.clear();
        adapter.notifyDataSetChanged();
    }
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    // 视图销毁时清空引用
    adapter = null;
    recyclerView = null;
    button = null;
    linearLayout = null;
}

方案2:用ViewModel分离数据与视图,保证数据一致性

通过ViewModel存储boxList,即使视图被销毁,数据也不会丢失,重新加载视图时自动复用数据:

  1. 创建OneViewModel:
public class OneViewModel extends ViewModel {
    private MutableLiveData<List<Box>> boxList = new MutableLiveData<>();

    public void initBoxList(int count) {
        List<Box> list = new ArrayList<>();
        for(int i=0; i<count; i++) {
            list.add(new Box(i+1, Mode.NOTCHECKED));
        }
        boxList.setValue(list);
    }

    public void clearBoxList() {
        List<Box> list = boxList.getValue();
        if (list != null) {
            list.clear();
            boxList.setValue(list);
        }
    }

    public LiveData<List<Box>> getBoxList() {
        return boxList;
    }
}
  1. 修改OneFragment,使用ViewModel管理数据:
public class OneFragment extends Fragment {
    Button button;
    RecyclerView recyclerView;
    BoxAdapter adapter;
    private OneViewModel viewModel;
    int t;

    // 推荐用newInstance传递参数,避免Fragment重建时参数丢失
    public static OneFragment newInstance(int k) {
        OneFragment fragment = new OneFragment();
        Bundle args = new Bundle();
        args.putInt("count", k);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewModel = new ViewModelProvider(this).get(OneViewModel.class);
        // 从参数中获取count
        if (getArguments() != null) {
            t = getArguments().getInt("count");
        }
        // 仅首次创建时初始化数据
        if (viewModel.getBoxList().getValue() == null) {
            viewModel.initBoxList(t);
        }
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_one, container, false);
        linearLayout = view.findViewById(R.id.linearlayout);
        button = view.findViewById(R.id.click);
        recyclerView = view.findViewById(R.id.recyclerview);

        // 观察数据变化,自动更新Adapter
        viewModel.getBoxList().observe(getViewLifecycleOwner(), newList -> {
            if (adapter == null) {
                adapter = new BoxAdapter(getActivity(), newList);
                recyclerView.setAdapter(adapter);
            } else {
                adapter.notifyDataSetChanged();
            }
        });

        button.setOnClickListener(v -> 
            Toast.makeText(getActivity(), "您点击了我。T= "+t, Toast.LENGTH_SHORT).show()
        );
        return view;
    }

    public void clearBox() {
        viewModel.clearBoxList();
    }

    public int getBoxSize() {
        List<Box> list = viewModel.getBoxList().getValue();
        return list != null ? list.size() : -1;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        adapter = null;
        recyclerView = null;
        button = null;
        linearLayout = null;
    }
}
  1. 修改HomeFragment中创建OneFragment的方式:
// 替换原来的new OneFragment(q)
oneFragment = OneFragment.newInstance(q);

方案3:避免直接持有Fragment引用,通过Adapter获取实例

修改HomeFragment的按钮点击事件,通过ViewPager2的Adapter获取有效OneFragment实例:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 通过Adapter获取位置0的OneFragment实例
        OneFragment targetFragment = (OneFragment) myAdapter.createFragment(0);
        if (targetFragment != null) {
            targetFragment.clearBox();
        }
    }
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 18:07:01