1

I am building this Android Application and I have this Activity where I have a ViewPager that hosts 4 different Fragments. The user can swipe among those fragments and see their data. I also have a menu where the user can delete or send records displayed on the 4 Fragments.

In order to figure out which fragment is active, I run this code (from the Activity where the viewPager is):

int activeItem = viewPager.getCurrentItem();
Log.e(TAG, "activeItem = " + activeItem);

Fragment fragment = this.getSupportFragmentManager().getFragments().get(activeItem);
String fragmentName = fragment.getClass().getSimpleName();

Log.e(TAG, "fragment name = " + fragmentName);

if(activeItem == 0) {
    showDialog("Confirm Send", "Would you like to send the checked items?",
            actionSend, RecordsSent, fragment);
}
else{
    showDialog("Confirm Send", "Would you like to send the checked items?",
            actionSend, RecordsPending, fragment);
}

What I do is I get the active item, then get the fragment at that index (using getSupportFragmentManager()). And then based on what the active item is, I have a good idea which Fragment is active.

This was working for quite some time until I added another fragment and all of a sudden, I was getting a ClassCastException. Because in my showDialog function, I do something like:

RecordsSent rsFragment = (RecordsSent) fragment;

And what was happening is that it was sending the wrong fragment! My fragments are:

RecordsSent RecordsPending RecordsSales RecordsNews

I was getting a Class Cast error because I was casting RecordsPending to RecordsSent and vice versa. I then listed my fragments with:

Log.e(TAG, "fragments = " + this.getSupportFragmentManager().getFragments().toString());

And then it showed RecordsPending first then RecordsSent. No wonder I was getting a ClassCastException. getCurrentItem was returning 0, and item 0 in the supportFragmentManager is RecordsPending instead of RecordsSent.

I don't know what prompted the switch between the indices of my Fragments, which makes this conundrum all the more puzzling.

Here's the code I used to initialize the Fragments.

TextView tv1 = createTab("Sent", new ColorDrawable(Color.parseColor("#006633")));
TextView tv2 = createTab("Pending", new ColorDrawable(Color.parseColor("#CCCC00")));
TextView tv3 = createTab("Daily Sales Report", new ColorDrawable(Color.parseColor("#F7C05F")));
TextView tv4 = createTab("News Records", new ColorDrawable(Color.parseColor("#B72153")));

tabLayout = (TabLayout) findViewById(R.id.tab_layout);
tabLayout.addTab(tabLayout.newTab().setCustomView(tv1).setTag("Sent"));
tabLayout.addTab(tabLayout.newTab().setCustomView(tv2).setTag("Pending"));
tabLayout.addTab(tabLayout.newTab().setCustomView(tv3).setTag("Sales"));
tabLayout.addTab(tabLayout.newTab().setCustomView(tv4).setTag("News"));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);

//more code here

viewPager = (ViewPager) findViewById(R.id.pager);
adapter = new PagerAdapter (getSupportFragmentManager(), tabLayout.getTabCount());
Log.e(TAG, "tab count = " + tabLayout.getTabCount());
viewPager.setAdapter(adapter);

viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        viewPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {

    }

    @Override
    public void onTabReselected(TabLayout.Tab tab) {

    }
});

My PagerAdapter class looks like this:

public class PagerAdapter extends FragmentStatePagerAdapter {
    int mNumOfTabs;

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

    @Override
    public Fragment getItem(int position) {

        switch (position) {
            case 0:
                RecordsSent tab1 = new RecordsSent();
                return tab1;
            case 1:
                RecordsPending tab2 = new RecordsPending();
                return tab2;
            case 2:
                RecordsSales tab3 = new RecordsSales();
                return tab3;
            case 3:
                RecordsNews tab4 = new RecordsNews();
                return tab4;
            default:
                return null;
        }
    }

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

As you can see, the first item is RecordsSent, then RecordsPending. I do not know why the supportFragmentManager returns the reverse order.

I tried:

android.support.v4.app.Fragment fragment = getVisibleFragment();
String fragmentName = fragment.getClass().getSimpleName();

but it still returns the wrong fragment type.

I also tried to do this inside my if-else blocks:

if(activeItem == 0) {
    Log.e(TAG, "fragment is records sent");
    fragment = fm.findFragmentByTag("Sent");

    showDialog(title, message,
            actionDelete, RecordsSent, fragment);

}
else{
    //I use "Pending" here
}

However, I get a null pointer exception when I force it.

This problem is really frustrating because it was working days ago and then suddenly it isn't.

halfer
  • 19,824
  • 17
  • 99
  • 186
Razgriz
  • 7,179
  • 17
  • 78
  • 150
  • `ViewPager.getCurrentItem()` returns an index of a fragment inside the ViewPager. `FragmentManager.getFragments()` represents any and all fragments added to the fragment manager. It's a black box and you have no control over the ordering. What made you think that one is interchangeable with the other? `FragmentManager.getFragments()` is not even part of public API. – Eugen Pechanec Oct 22 '16 at 10:14
  • What would you suggest I do to get the active fragment inside a viewpager? – Razgriz Oct 22 '16 at 10:19
  • Each fragment can provide its own menu items. See http://stackoverflow.com/questions/18714322/how-to-add-action-bar-options-menu-in-android-fragments. If you have some common code for all fragments, extract it to an abstract super class. – Eugen Pechanec Oct 22 '16 at 10:24
  • Thanks for the lead. I'll definitely give this a shot. – Razgriz Oct 22 '16 at 10:26
  • @EugenPechanec But how do you suggest I go about solving the original problem? I am using a customlistview adapter for both those fragments and the listview adapter has a checkbox. I am using the custom adapter to track the change in check state and then call the necessary fragment to update which indices are checked or not. – Razgriz Oct 22 '16 at 10:47
  • Your original post does not mention anything about a list view or adapter. Please post another question, let's focus on one thing at a time. – Eugen Pechanec Oct 22 '16 at 12:33
  • @EugenPechanec new question here: http://stackoverflow.com/questions/40195736/android-find-out-active-fragment-from-customlistadapter – Razgriz Oct 22 '16 at 19:10

0 Answers0