android – How can i set a tag for viewpager fragments?-ThrowExceptions

Exception or error:

I,m using slidingTabLayout with 4 tabs and a viewpager and 4 fragment class for every tab.

i need to reload one of my fragments (first tab) in my project when user click some button, and for this i need to have a tag for that fragment

my question is : how can i set a tag for one of viewpagers fragment???

My MainActivity tab and viewpager codes:

public class MainActivity extends AppCompatActivity
    implements NavigationView.OnNavigationItemSelectedListener {



Toolbar toolbar;
ViewPager pager;
ViewPagerAdapter adapter;
SlidingTabLayout tabs;
CharSequence Titles[]={"نوع","قیمت","برند","همه"};
int Numboftabs = 4;




@Override
protected void attachBaseContext(Context newBase) {
    super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}



@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);




    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "درج آگهی رایگان", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });



    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);

    NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
    navigationView.setNavigationItemSelectedListener(this);




    // Creating The ViewPagerAdapter and Passing Fragment Manager, Titles fot the Tabs and Number Of Tabs.
    adapter =  new ViewPagerAdapter(getSupportFragmentManager(),Titles,Numboftabs);

    // Assigning ViewPager View and setting the adapter
    pager = (ViewPager) findViewById(R.id.pager);
    pager.setAdapter(adapter);

    // Assiging the Sliding Tab Layout View
    tabs = (SlidingTabLayout) findViewById(R.id.tabs);
    tabs.setDistributeEvenly(true); // To make the Tabs Fixed set this true, This makes the tabs Space Evenly in Available width

    // Setting Custom Color for the Scroll bar indicator of the Tab View
    tabs.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
        @Override
        public int getIndicatorColor(int position) {
            return getResources().getColor(R.color.colorWhite);
        }
    });

    // Setting the ViewPager For the SlidingTabsLayout
    tabs.setViewPager(pager);
    pager.setCurrentItem(3);




} and ....

Thank you a lot

How to solve:

There are couple of solution for this.

1). When the FragmentPagerAdapter adds a Fragment to the FragmentManager, it uses a special tag based on the particular position that the Fragment will be placed. So you can simply get the current visible Fragment in your ViewPager using these lines of code

 Fragment fragment = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + ViewPager.getCurrentItem());
 // based on the current position you can then cast the page to the correct Fragment class and call some method inside that fragment to reload the data:
 if (0 == ViewPager.getCurrentItem() && null != fragment) {
      ((TabFragment1)fragment).reloadFragmentData();     
 } 

2). You should keep track of all the active fragments in the FragmentStatePagerAdapter. For demo sample you can refer to second approach here

3). You can make use of EventBus to post events to your Fragment from anywhere. All you have to do is to register your Fragment for that specific event. For official documentation refer this

###

Here is the method which is used by FragmentPagerAdapter to create the Fragment‘s tag name:

private static String makeFragmentName(int viewId, long id) {
    return "android:switcher:" + viewId + ":" + id;
}

viewId is the id of the ViewPager.
id is the position of the fragment inside the ViewPager.

Example:

String fragmentTag = makeFragmentName(myViewPager.getId(), 2);
Fragment fragment = getSupportFragmentManager().findFragmentByTag(fragmentTag);

###

Though this question has already been answered. I have another approach for achiving this and this might be better one as the way fragments are tagged in the code are subjected to change. Also to point out using adapter.getItem(position) does not return the instance of fragment being displayed, it will depend on our own implementation of getItem method.

So Basically the problem is that we do not have the instance of Fragments that are present in the viewPager. The idea is to override method

public Object instantiateItem(ViewGroup container, int position) {
    // If we already have this item instantiated, there is nothing
    // to do.  This can happen when we are restoring the entire pager
    // from its saved state, where the fragment manager has already
    // taken care of restoring the fragments we previously had instantiated.
    if (mFragments.size() > position) {
        Fragment f = mFragments.get(position);
        if (f != null) {
            return f;
        }
    }

    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }

    Fragment fragment = getItem(position);
    if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
    if (mSavedState.size() > position) {
        Fragment.SavedState fss = mSavedState.get(position);
        if (fss != null) {
            fragment.setInitialSavedState(fss);
        }
    }
    while (mFragments.size() <= position) {
        mFragments.add(null);
    }
    fragment.setMenuVisibility(false);
    fragment.setUserVisibleHint(false);
    mFragments.set(position, fragment);
    mCurTransaction.add(container.getId(), fragment);

    return fragment;
}

of FragmentStatePagerAdapter. If we look at the default implementation of this method, it basically does the job of instantiating new Fragments if they do not exists and returning them. Also it stores them in a list of fragments which is private. So what we can do is Override this method and store the instances on fragments in our own list. This can be implemented in the following way

private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {

    private ArrayList<Fragment> fragmentList;

    private final int NUM_PAGES;

    public ScreenSlidePagerAdapter(FragmentManager fm, int numPages) {
        super(fm);
        NUM_PAGES = numPages;
        fragmentList = new ArrayList<>(NUM_PAGES);
    }

    @Override
    public Fragment getItem(int position) {
        Fragment fragment = new CustomFragment();
        //this method can be modified according to the requirement
        return fragment;
    }

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

    public Fragment getFragment(int position){
        return fragmentList.get(position);
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position){
        Fragment fragment = (Fragment) super.instantiateItem(container,position);
        if(fragmentList.size()<NUM_PAGES&&!fragmentList.contains(fragment)){
            fragmentList.add(fragment);
        }
        return fragment;
    }
}

Therefore we will have the instances of all the fragments available with us we would no longer need any tags to find the fragment instances being displayed to the user.

Leave a Reply

Your email address will not be published. Required fields are marked *