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

EditText+ViewPager2实现Fragment传值报错及替代方案咨询

问题描述

我在第一个Fragment里用EditText输入整数值,通过Integer.parseInt转换后,尝试用接口把值传到第二个Fragment,项目里用了ViewPager2,这是我第一次用ViewPager,经验不足。现在有两个问题:

  1. 代码运行报错,错误在SM.sendData(Integer.parseInt(text1.getText().toString()));,不知道原因;
  2. 有没有其他传值方式,比如用Bundle?

First Fragment代码

public class FirstFragment extends Fragment {

    private FragmentFirstBinding binding;
    SendMessage SM;

    @Override
    public View onCreateView(
            @NonNull LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState
    ) {

        binding = FragmentFirstBinding.inflate(inflater, container, false);
        return binding.getRoot();

    }

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        final EditText text1 = view.findViewById(R.id.text1);

        binding.buttonFirst.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SM.sendData(Integer.parseInt(text1.getText().toString()));
                NavHostFragment.findNavController(FirstFragment.this)
                       .navigate(R.id.action_FirstFragment_to_SecondFragment);
            }
        });
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }

    interface SendMessage {
        void sendData(int number);
    }

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);

        try {
            SM = (SendMessage) getActivity();
        } catch (ClassCastException e) {
            throw new ClassCastException("Error in retrieving data. Please try again");
        }
    }

}

Second Fragment代码

public class SecondFragment extends Fragment {

    private FragmentSecondBinding binding;
    TextView textView;

    @Override
    public View onCreateView(
            @NonNull LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState
    ) {

        binding = FragmentSecondBinding.inflate(inflater, container, false);
        return binding.getRoot();

    }

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        textView = view.findViewById(R.id.score_result);

        binding.buttonSecond.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                NavHostFragment.findNavController(SecondFragment.this).navigate(R.id.action_SecondFragment_to_FirstFragment);
            }
        });
    }

    protected void displayReceivedData(int number)
    {
        textView.setText(number);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }

}

ViewPager Adapter代码

public class ViewPagerAdapter extends FragmentStateAdapter {
    public ViewPagerAdapter(FragmentManager fm, Lifecycle behavior) {
        super(fm,behavior);
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        Fragment fragment = null;
        if (position == 0) {
            fragment = new FirstFragment();
        } else if (position == 1) {
            fragment = new SecondFragment();
        }
        assert fragment != null;
        return fragment;
    }

    @Override
    public int getItemCount() {
        return 2;
    }
}

Main Activity代码

public class MainActivity extends AppCompatActivity implements FirstFragment.SendMessage{

    ViewPager2 viewPager;
    ViewPagerAdapter viewPagerAdapter;
    private AppBarConfiguration appBarConfiguration;
    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        setSupportActionBar(binding.toolbar);

        viewPager = findViewById(R.id.viewPager2);
        viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager(),getLifecycle());
        viewPager.setAdapter(viewPagerAdapter);

        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
    }

    @Override
    public void sendData(int number) {
        SecondFragment secondFragment=new SecondFragment();
        SecondFragment f = (SecondFragment) getSupportFragmentManager().findFragmentByTag(String.valueOf(secondFragment));
        f.displayReceivedData(number);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_status) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        return NavigationUI.navigateUp(navController, appBarConfiguration)
                || super.onSupportNavigateUp();
    }
}

问题解答

第一个错误的原因及修复

报错核心原因

  1. 输入非法导致格式异常:EditText为空或输入非数字内容时,Integer.parseInt会抛出NumberFormatException;
  2. 获取SecondFragment实例失败:你在sendData里新建了一个SecondFragment实例,用它的toString值查找Fragment,根本找不到ViewPager中已加载的实例,导致f为空,调用方法时触发空指针;
  3. setText方法误用:textView.setText(number)会把整数当成资源ID,而非文本内容,会触发资源找不到的崩溃;
  4. 方法访问权限问题:SecondFragment的displayReceivedData是protected修饰,外部无法直接调用。

修复步骤

  1. 校验EditText输入合法性:
binding.buttonFirst.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        String input = text1.getText().toString().trim();
        if (input.isEmpty()) {
            Toast.makeText(requireContext(), "请输入数字", Toast.LENGTH_SHORT).show();
            return;
        }
        try {
            int number = Integer.parseInt(input);
            SM.sendData(number);
            NavHostFragment.findNavController(FirstFragment.this)
                   .navigate(R.id.action_FirstFragment_to_SecondFragment);
        } catch (NumberFormatException e) {
            Toast.makeText(requireContext(), "请输入有效的整数", Toast.LENGTH_SHORT).show();
        }
    }
});
  1. 正确获取ViewPager中的SecondFragment:FragmentStateAdapter创建的Fragment标签格式为f{position},直接按位置查找:
@Override
public void sendData(int number) {
    // 查找ViewPager中位置1的SecondFragment实例
    String tag = "f1";
    SecondFragment f = (SecondFragment) getSupportFragmentManager().findFragmentByTag(tag);
    if (f != null && f.isAdded()) {
        f.displayReceivedData(number);
    }
}
  1. 修改SecondFragment的方法权限与setText逻辑:
// 改成public权限
public void displayReceivedData(int number) {
    // 把整数转为字符串,避免当成资源ID
    textView.setText(String.valueOf(number));
}

其他传值方式(含Bundle)

1. ViewModel共享数据(推荐ViewPager场景)

ViewModel可以在Activity的生命周期内共享数据,适合ViewPager这种多Fragment共存的场景:

  • 创建共享ViewModel:
public class SharedViewModel extends ViewModel {
    private final MutableLiveData<Integer> numberData = new MutableLiveData<>();

    public void setNumber(int number) {
        numberData.setValue(number);
    }

    public LiveData<Integer> getNumber() {
        return numberData;
    }
}
  • FirstFragment设置数据:
binding.buttonFirst.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        String input = text1.getText().toString().trim();
        if (input.isEmpty()) {
            Toast.makeText(requireContext(), "请输入数字", Toast.LENGTH_SHORT).show();
            return;
        }
        try {
            int number = Integer.parseInt(input);
            SharedViewModel viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
            viewModel.setNumber(number);
            NavHostFragment.findNavController(FirstFragment.this)
                   .navigate(R.id.action_FirstFragment_to_SecondFragment);
        } catch (NumberFormatException e) {
            Toast.makeText(requireContext(), "请输入有效的整数", Toast.LENGTH_SHORT).show();
        }
    }
});
  • SecondFragment观察数据:
@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    textView = view.findViewById(R.id.score_result);

    SharedViewModel viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
    viewModel.getNumber().observe(getViewLifecycleOwner(), number -> {
        textView.setText(String.valueOf(number));
    });

    // 原有按钮逻辑...
}

2. Bundle传递(适合Navigation跳转场景)

通过Navigation跳转时直接携带Bundle:

  • FirstFragment传递数据:
binding.buttonFirst.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        String input = text1.getText().toString().trim();
        if (input.isEmpty()) {
            Toast.makeText(requireContext(), "请输入数字", Toast.LENGTH_SHORT).show();
            return;
        }
        try {
            int number = Integer.parseInt(input);
            Bundle bundle = new Bundle();
            bundle.putInt("KEY_NUMBER", number);
            NavHostFragment.findNavController(FirstFragment.this)
                   .navigate(R.id.action_FirstFragment_to_SecondFragment, bundle);
        } catch (NumberFormatException e) {
            Toast.makeText(requireContext(), "请输入有效的整数", Toast.LENGTH_SHORT).show();
        }
    }
});
  • SecondFragment接收数据:
@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    textView = view.findViewById(R.id.score_result);

    if (getArguments() != null) {
        int number = getArguments().getInt("KEY_NUMBER", 0);
        textView.setText(String.valueOf(number));
    }

    // 原有按钮逻辑...
}

3. 接口回调(已修复的原有方式)

就是你最初使用的接口传值,只要完成前面的错误修复,就能正常工作。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 10:25:18