Search code examples
javaandroidandroid-fragmentsandroid-tablayout

app crashes when swipe to new fragment and swipe back to previous fragment in tabLayout


I have a Main fragment that contains two fragments (fragment A & B), and above in the toolBar there is a search icon for search purpose. My problem is when I just only swipe between fragment A & B and use the search icon to do some search filter, the app works OK. But the problem is when I add another new fragment C in the Main fragment, after starting the app and swipe to fragment C then swipe back to fragment A or B, then click the search icon, the app crashed.

Here is the crash log

2019-03-07 22:52:10.616 28866-28866/com.example.welsenho.questfy_tw E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.welsenho.questfy_tw, PID: 28866 java.lang.ClassCastException: com.example.welsenho.questfy_tw.MainActivityFragment.MostPopularFragment cannot be cast to com.example.welsenho.questfy_tw.MainActivityFragment.MainActivityLatestArticleFragment at com.example.welsenho.questfy_tw.MainUserActivity.MainActivity.searchFilter(MainActivity.java:303) at com.example.welsenho.questfy_tw.MainUserActivity.MainActivity.access$200(MainActivity.java:50) at com.example.welsenho.questfy_tw.MainUserActivity.MainActivity$1.onQueryTextChange(MainActivity.java:158) at android.support.v7.widget.SearchView.onTextChanged(SearchView.java:1181) at android.support.v7.widget.SearchView$10.onTextChanged(SearchView.java:1715) at android.widget.TextView.sendOnTextChanged(TextView.java:9364) at android.widget.TextView.setText(TextView.java:5397) at android.widget.TextView.setText(TextView.java:5250) at android.widget.EditText.setText(EditText.java:113) at android.widget.TextView.setText(TextView.java:5207) at android.support.v7.widget.SearchView.onActionViewExpanded(SearchView.java:1295) at android.support.v7.widget.Toolbar$ExpandedActionViewMenuPresenter.expandItemActionView(Toolbar.java:2397)

It says that Fragment A cannot be cast to Fragment B, but what I don't understand is that if I did not swipe to Fragment C (Just between Fragment A & B) everything will be just fine but after swiping to Fragment C and swipe back to Fragment A or B and click the search icon then the app will crash

code for the Main Activity

private void searchFilter(String inputText, ArrayList<FirebaseDatabaseGetSet> decidedFilterList) {
    Log.d("TAG", "searchFilter");
    ArrayList<FirebaseDatabaseGetSet> filterList = new ArrayList<>();
    if (!filterList.isEmpty()) {
        filterList.clear();
    }

    MainActivityLatestArticleFragment latestArticleFragment;
    MostPopularFragment mostPopularFragment;
    MainSubjectChooseFragment mainSubjectChooseFragment;

    //MainSubjectChooseFragment mainSubjectChooseFragment(Fragment C) = (MainSubjectChooseFragment) getSupportFragmentManager().getFragments().get(0).getChildFragmentManager() .getFragments().get(2);
    latestArticleFragment(Fragment A) = (MainActivityLatestArticleFragment) getSupportFragmentManager().getFragments().get(0).getChildFragmentManager().getFragments().get(0);
    mostPopularFragment(Fragment B) = (MostPopularFragment) getSupportFragmentManager().getFragments().get(0).getChildFragmentManager().getFragments().get(1);

    Log.d("TAG", "Fragment");

    for (FirebaseDatabaseGetSet firebaseDatabaseGetSet : decidedFilterList) {
        if (firebaseDatabaseGetSet.getTitle().toLowerCase().contains(inputText.toLowerCase())) {
            filterList.add(firebaseDatabaseGetSet);
            if (currentFilterPage == 0) {
                Log.d("TAG", "Fragment0");
                if (latestArticleFragment != null) {
                    Log.d("TAG", "notNull");
                    if (!filterList.isEmpty()) {
                        Log.d("TAG", "filter");
                        latestArticleFragment.returnFilterList(filterList);
                    }
                }
            } else if (currentFilterPage == 1) {
                Log.d("TAG", "Fragment1");
                if (mostPopularFragment != null) {
                    if (!filterList.isEmpty()) {
                        mostPopularFragment.returnFilterList(filterList);
                    }
                }
            }
        }
    }

}

code for Main Fragment

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_main_activity_tab, container, false);
    tabLayout = view.findViewById(R.id.main_activity_tabLayout);
    viewPager = view.findViewById(R.id.main_activity_viewpager);
    viewPager.setAdapter(new MainActivityTabAdapter(getChildFragmentManager(), Locale.getDefault().getDisplayLanguage()));
    tabLayout.post(new Runnable() {
        @Override
        public void run() {
            tabLayout.setupWithViewPager(viewPager);
        }
    });

    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int i, float v, int i1) {
            mListener.getTabCurrentPage(i);
        }

        @Override
        public void onPageSelected(int i) {
            mListener.getTabCurrentPage(i);
        }

        @Override
        public void onPageScrollStateChanged(int i) {

        }
    });
    return view;

code for the adapter

@Override
public Fragment getItem(int i) {
    switch (i){
        case 0: return new MainActivityLatestArticleFragment();
        case 1: return new MostPopularFragment();
        case 2: return new MainSubjectChooseFragment();
    }
    return null;
}

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

@Nullable
@Override
public CharSequence getPageTitle(int position) {
    if (language.equals("中文")) {
        switch (position) {
            case 0:
                return "最新文章";
            case 1:
                return "熱門文章";
            case 2:
                return "相關科系";
        }
    }else {
        switch (position) {
            case 0:
                return "Latest Article";
            case 1:
                return "Most Popular";
            case 2:
                return "Program Select";
        }
    }
    return null;
}

code in Fragment A & B are just for only retrieving data from firebase and load into recyclerView. It says the problem was cause by this line latestArticleFragment(Fragment A) = (MainActivityLatestArticleFragment) getSupportFragmentManager().getFragments().get(0).getChildFragmentManager().getFragments().get(0); part, but I don't get it is that when I'm not trying to swipe to Fragment C everything works smoothly, but if I did swipe to Fragment C and swipe back to Fragment A & B then click the search icon the app will crashed. I have beed bothered by this problem for like 3 days already and tried some solution but it just can not work. Can anyone explain why I am having this problem and how I can fix it?


Solution

  • My hunch is if you set off screen page limit to more than 1, you will not face the issue. So in your MainFragment's onCreateView add the following one line:

    viewPager = view.findViewById(R.id.main_activity_viewpager);
    // add below line
    viewpager.setOffscreenPageLimit(2)
    viewPager.setAdapter(new MainActivityTabAdapter(getChildFragmentManager(), Locale.getDefault().getDisplayLanguage()));