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

Android:MainActivity托管的Fragment间传值遇空指针异常求助

问题分析

你的Null Pointer Exception和数据传递失败的核心原因:

  • 在frag1的按钮点击事件中,你新建了一个frag2实例并设置Arguments,但这个实例和ViewPager2中实际显示的frag2实例完全是两个对象。ViewPager2的Fragment实例由viewPagerAdapter负责创建和管理,你手动new的实例从未被添加到界面中,所以目标frag2根本接收不到参数。
  • ViewPager2默认会预加载相邻页面,frag2可能在你点击按钮前就已经被创建,此时即使修改adapter的创建逻辑,也需要考虑生命周期的适配问题。
解决方案:使用共享ViewModel(官方推荐)

Google官方推荐用ViewModel实现Fragment间通信,尤其是ViewPager场景下,无需依赖Activity中转,数据可直接在Fragment间共享。

步骤1:创建共享ViewModel

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

public class SharedViewModel extends ViewModel {
    private final MutableLiveData<String> sharedText = new MutableLiveData<>();

    public void setSharedText(String text) {
        sharedText.setValue(text);
    }

    public MutableLiveData<String> getSharedText() {
        return sharedText;
    }
}

步骤2:修改frag1的按钮逻辑

不再手动创建frag2实例,改为通过ViewModel传递数据:

public class frag1 extends Fragment {
    private EditText editText;
    private Button button;
    private SharedViewModel viewModel;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_frag1, container, false);

        // 初始化共享ViewModel
        viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);

        editText = view.findViewById(R.id.frag1ET);
        button = view.findViewById(R.id.frag1btn);

        button.setOnClickListener(v -> {
            String text = editText.getText().toString();
            // 通过ViewModel传递数据
            viewModel.setSharedText(text);
            editText.setText("");
        });

        return view;
    }
}

步骤3:修改frag2接收数据逻辑

通过ViewModel观察数据变化,实时更新UI:

public class frag2 extends Fragment {
    private TextView tv2;
    private SharedViewModel viewModel;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_frag2, container, false);

        tv2 = view.findViewById(R.id.frag2tv);
        // 初始化共享ViewModel
        viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);

        return view;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        // 观察数据变化,自动更新UI
        viewModel.getSharedText().observe(getViewLifecycleOwner(), text -> {
            tv2.setText(text != null && !text.isEmpty() ? text : "Text not received");
        });
    }
}
替代方案:Activity中转(接口回调)

如果不想用ViewModel,可通过Activity作为中间层传递数据:

步骤1:定义回调接口

public interface OnDataPassListener {
    void onDataPass(String data);
}

步骤2:让MainActivity实现接口并保存frag2实例

public class MainActivity extends AppCompatActivity implements OnDataPassListener {
    private viewPagerAdapter vpa;
    private frag2 frag2Instance;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tb=findViewById(R.id.tab_lyt);
        vp= findViewById(R.id.pager);
        
        // 修改adapter创建逻辑,保存frag2实例
        vpa = new viewPagerAdapter(this) {
            @NonNull
            @Override
            public Fragment createFragment(int position) {
                if (position == 1) {
                    frag2Instance = new frag2();
                    return frag2Instance;
                }
                return new frag1();
            }
        };
        vp.setAdapter(vpa);

        // ... 原有TabLayout和ViewPager2监听代码不变
    }

    @Override
    public void onDataPass(String data) {
        if (frag2Instance != null) {
            frag2Instance.updateText(data);
        }
    }
}

步骤3:修改frag1传递数据

public class frag1 extends Fragment {
    private OnDataPassListener listener;

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        if (context instanceof OnDataPassListener) {
            listener = (OnDataPassListener) context;
        } else {
            throw new RuntimeException(context.toString() + " must implement OnDataPassListener");
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_frag1, container, false);

        editText = view.findViewById(R.id.frag1ET);
        button = view.findViewById(R.id.frag1btn);

        button.setOnClickListener(v -> {
            String text = editText.getText().toString();
            listener.onDataPass(text);
            editText.setText("");
        });

        return view;
    }
}

步骤4:在frag2中添加更新方法

public class frag2 extends Fragment {
    private TextView tv2;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_frag2, container, false);
        tv2 = view.findViewById(R.id.frag2tv);
        return view;
    }

    // 供外部调用更新文本
    public void updateText(String text) {
        if (tv2 != null) {
            tv2.setText(text);
        }
    }
}
注意事项
  • 不推荐通过修改Fragment的arguments传递动态数据,arguments仅适用于初始化Fragment时的静态参数传递。
  • ViewPager2的FragmentStateAdapter会根据页面状态销毁/重建Fragment,直接保存Fragment实例的方式有局限性,ViewModel是更可靠的长期方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 01:54:52