I am using EventBus to navigate from one fragment to another after a button click. Sometimes and not reproducible the following error comes up:
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)
There are some answers to that problem but nothing worked for me since I am using EventBus.
Here is the Fragment that apparently already have been added:
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();
}
}
I am using this 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;
}
}
Within each question I have a second ViewPager, so there is a ViewPager within a ViewPager, here is the second 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;
}
}
This is my class I call to open the next fragment:
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;
}
}
I am using this call EventBus.getDefault().post(new SetQuestionAdapterPosition(1));
to open the next fragment. Can I use the following code to prevent the app to crash?
try {
EventBus.getDefault().post(new SetQuestionAdapterPosition(1));
} catch (Exception e){
Log.e("Answer2", e.toString());
}
Is there something I can add in my code so before adding the fragment it checks if its already been added to prevent the error statement?
I appreciate every help and suggestion!