【问题标题】:"Fragment already added" occurs sometimes while using EventBus with ViewPager将 EventBus 与 ViewPager 一起使用时,有时会出现“已添加片段”
【发布时间】:2020-07-27 14:35:42
【问题描述】:

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

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,所以对我没有任何帮助。

这是显然已经添加的片段:

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;
    }
}

这是我为打开下一个片段而调用的班级:

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));打开下一个片段。我可以使用以下代码来防止应用崩溃吗?

        try {
            EventBus.getDefault().post(new SetQuestionAdapterPosition(1));
        } catch (Exception e){
            Log.e("Answer2", e.toString());
        }

有什么我可以在我的代码中添加的东西,所以在添加片段之前它会检查它是否已经被添加以防止错误语句?

感谢每一个帮助和建议!

【问题讨论】:

  • 你为什么使用事件总线?这是要求吗? Android 有 graphNavigation,它更加简化了这一点。

标签: java android android-fragments event-bus


【解决方案1】:

EventBus 经常会引入意大利面条式的代码,这种情况很可能是由于事件在意外触发时造成的。你没有在EventBus.getDefault().post() 发生时发布整个逻辑,但我强烈建议仔细检查为什么它会触发同一个片段两次。

但是,一个简单(但很麻烦)的解决方法是在使用 Fragment.isAdded() 添加之前检查片段是否已添加:

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

【讨论】:

  • 我同意,OP 应该看看为什么该事件被发布两次。解决方案是“hacky”(你的话不是我的话)。 ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-27
  • 2017-10-13
  • 2020-01-17
相关资源
最近更新 更多