java - "Fragment already added"有时在将 EventBus 与 ViewPager 一起使用时发生

标签 java android android-fragments event-bus

单击按钮后,我正在使用 EventBus 从一个 fragment 导航到另一个 fragment 。有时会出现以下错误且不可重现:

Fatal Exception: java.lang.IllegalStateException: Fragment already added: FragmentQuestion3_2{82d0763} (e57d5f9c-c80b-4f99-a4f4-e844bdabdef5) id=0x7f0a0487}
       at androidx.fragment.app.FragmentStore.addFragment(FragmentStore.java:67)
       at androidx.fragment.app.FragmentManager.addFragment(FragmentManager.java:1563)
       at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:405)
       at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2167)
       at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1990)
       at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1945)
       at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1847)
       at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
       at android.os.Handler.handleCallback(Handler.java:873)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:216)
       at android.app.ActivityThread.main(ActivityThread.java:7211)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)
这个问题有一些答案,但因为我使用的是 EventBus,所以对我没有任何帮助。
这是显然已经添加的 fragment :
public class FragmentQuestion3_2 extends BaseFragment {

    private ViewModelQuestionAnswer viewModel;
    private String category;
    private ImageView imageCategory;
    private TextView question3;

    PagerAdapter viewPagerAdapter;
    public NonSwipeAbleViewPager optionAnswerViewPager;

    private boolean isFragmentLoaded = false;

    public FragmentQuestion3_2() {
        // Required empty public constructor
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        EventBus.getDefault().register(this);
    }

    public static FragmentQuestion3_2 newInstance(String questionNumber) {
        return new FragmentQuestion3_2();
    }

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

        // init ViewModel
        viewModel = ViewModelProviders.of(requireActivity()).get(ViewModelQuestionAnswer.class);
    }

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

        View view = inflater.inflate(R.layout.fragment_question, container, false);

        imageCategory = view.findViewById(R.id.image_view_question);
        question3 = view.findViewById(R.id.question);
        optionAnswerViewPager = view.findViewById(R.id.option_answer_view_pager);

        // Gets the category so the ImageView can be updated accordingly
        viewModel.getCategory().observe(requireActivity(), new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {

                category = s;

                setUpCategoryImage();

            }
        });

        // Gets the question
        viewModel.getQuestion3().observe(requireActivity(), new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                question3.setText(s);

            }
        });

        return view;
    }

    @Override
    public void onResume() {
        super.onResume();
        if (!isFragmentLoaded) {
            isFragmentLoaded = true;
            init();
        }
    }

    private void initOptionAnswerViewPager() {
        viewPagerAdapter = new ViewPagerOptions3Round2(getChildFragmentManager(), 2);
        Utils.getInstance().changePagerScroller(optionAnswerViewPager);
        optionAnswerViewPager.setAdapter(viewPagerAdapter);
        optionAnswerViewPager.setPagingEnabled(false);
        optionAnswerViewPager.setOffscreenPageLimit(3);
    }

    @Override
    protected void setupListeners() {

    }

    @Subscribe
    public void setViewPagerPosition(SetViewPagerPosition setViewPagerPosition) {
        optionAnswerViewPager.setCurrentItem(setViewPagerPosition.getPosition(), true);
    }

    @Override
    public void init() {

        initOptionAnswerViewPager();

    }
    @Override
    public void onDetach() {
        EventBus.getDefault().unregister(this);
        super.onDetach();
    }
}
我正在使用这个 FragmentStatePagerAdapter:
public class QuestionsPagerAdapterRound2 extends FragmentStatePagerAdapter {
    private static final String QUESTION_NUMBER = "question_number";

    private int mNumOfTabs;
    private final List<Fragment> mFragmentList = new ArrayList<>();


    public QuestionsPagerAdapterRound2(FragmentManager fm, int NumOfTabs) {
        super(fm, FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
        this.mNumOfTabs = NumOfTabs;
    }

    public void addFragment(Fragment fragment) {
        mFragmentList.add(fragment);
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                return FragmentCategory_2.newInstance("1");
            case 1:
                return FragmentQuestion1_2.newInstance("2");
            case 2:
                return FragmentQuestion2_2.newInstance("3");
            case 3:
                return FragmentQuestion3_2.newInstance("4");
            case 4:
                return FragmentQuestionResult_2.newInstance("5");

            default:
                return null;
        }
    }

    @Override
    public int getCount() {
        return mNumOfTabs;
    }

    @Override
    public int getItemPosition(Object object) {
        return PagerAdapter.POSITION_NONE;
    }
}
在每个问题中,我都有第二个 ViewPager,因此 ViewPager 中有一个 ViewPager,这是第二个 ViewPager:
public class ViewPagerOptions3Round2 extends FragmentStatePagerAdapter {

    private int mNumOfTabs;
    private final List<Fragment> mFragmentList = new ArrayList<>();


    public ViewPagerOptions3Round2(FragmentManager fm, int NumOfTabs) {
        super(fm, FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
        this.mNumOfTabs = NumOfTabs;
    }

    public void addFragment(Fragment fragment) {
        mFragmentList.add(fragment);
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                return FragmentOptions3.newInstance();
            case 1:
                return FragmentAnswer3_2.newInstance();
            default:
                return null;
        }
    }

    @Override
    public int getCount() {
        return mNumOfTabs;
    }

    @Override
    public int getItemPosition(Object object) {
        return PagerAdapter.POSITION_NONE;
    }
}
这是我为打开下一个 fragment 而调用的类(class):
public class SetQuestionAdapterPosition {

    private Integer position;

    public Integer getPosition() {
        return position;
    }

    public void setPosition(Integer position) {
        this.position = position;
    }

    public SetQuestionAdapterPosition(Integer position) {
        this.position = position;
    }

}
我正在使用这个电话 EventBus.getDefault().post(new SetQuestionAdapterPosition(1));打开下一个 fragment 。我可以使用以下代码来防止应用程序崩溃吗?
        try {
            EventBus.getDefault().post(new SetQuestionAdapterPosition(1));
        } catch (Exception e){
            Log.e("Answer2", e.toString());
        }
有什么我可以在我的代码中添加的东西,所以在添加 fragment 之前它会检查它是否已经被添加以防止错误语句?
我感谢每一个帮助和建议!

最佳答案

EventBus 经常会引入意大利面条式的代码,这种情况很可能是由于事件在非预期时间触发造成的。您没有在 EventBus.getDefault().post() 时发布整个逻辑。发生了,但我强烈建议仔细检查为什么它会触发同一个 fragment 两次。
然而,一个简单(但很麻烦)的修复方法是在使用 Fragment.isAdded() 添加之前检查 fragment 是否已经添加。 :

public void addFragment(Fragment fragment) {
    if (!fragment.isAdded()) {
        mFragmentList.add(fragment);
    }
}

关于java - "Fragment already added"有时在将 EventBus 与 ViewPager 一起使用时发生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63117607/

相关文章:

java - Scene2d 在 table 顶部添加 Actor

java - 我应该使用 AsyncTask 还是 IntentService 进行 REST API 调用?

java - 如何将 Intent 发送到 gameView

android - 导航到Android中的另一个 fragment 后如何清除导航堆栈

java - Linux下查看当前网络速度

java - 每次页面请求后conversationId不断增加是否正常?

java - 注释不可见?

android - 调用Handler时是否需要调用Looper.prepare()

java - 如何制作每天显示一次的自定义对话框

android - 如何显示向上滑动面板展开?