问题描述

我在安卓开发中出现了按钮绑定事件混乱的问题。页面结构是:

MainActivity:
   tab1:
       Fragment1(包含一个ConfigEditFragment)
   tab2:
       Fragment2(包含一个ConfigEditFragment)

每个 ConfigEditFragment 都有一个刷新按钮,点击后调用从父级元素传过来的回调函数。现在的问题是无论我点击的是 Fragment1 的刷新按钮还是 Fragment2 的刷新按钮,触发的都是 test2()。而这两个 Fragment 里包含的 ConfigEditFragment 也确实是不同的内容。请问这是什么原因?

public class Fragment1 extends Fragment {

    private ConfigEditorFragment configFragment1 = null;

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

        View rootView = inflater.inflate(R.layout.fragment1_page, container, false);

        Context context = requireContext();

        FragmentTransaction ft = getParentFragmentManager().beginTransaction();
        configFragment1 = ConfigEditorFragment.newInstance(new Data1(), this::test1);
        ft.replace(R.id.fragment1_container, configFragment1, "config_fragment_1");
        ft.commit();

        return rootView;
    }

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

    private void test1() {
        Toast.makeText(requireContext(), "Fragment1 test1 called", Toast.LENGTH_SHORT).show();
    }
public class Fragment2 extends Fragment {

    private ConfigEditorFragment configFragment2 = null;

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

        View rootView = inflater.inflate(R.layout.fragment2_page, container, false);

        Context context = requireContext();

        FragmentTransaction ft = getParentFragmentManager().beginTransaction();
        configFragment2 = ConfigEditorFragment.newInstance(new Data2(), this::test2);
        ft.replace(R.id.fragment2_container, configFragment2, "config_fragment_2");
        ft.commit();

        return rootView;
    }

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

    private void test2() {
        Toast.makeText(requireContext(), "Fragment2 test2 called", Toast.LENGTH_SHORT).show();
    }

public class MainPagerAdapter extends FragmentStateAdapter {

    public MainPagerAdapter(@NonNull FragmentActivity fragmentActivity) {
        super(fragmentActivity);
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        switch (position) {
            case 0:
                return new SettingsFragment();
            case 1:
                return new Fragment1();
            default:
                return new Fragment2();
        }
    }

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

原因

Fragment 管理层级 + FragmentManager 用错了,导致同一个 ConfigEditorFragment 实例被复用 / 覆盖问题,从而按钮事件指向了最后一次绑定的回调(Location 的)。

解决方案

getParentFragmentManager() 改为 getChildFragmentManager()