Rishabh Agrawal
Rishabh Agrawal

Reputation: 901

getItem() method is getting called twice when using Fragment Pager Adaptor

I am using a fragment pager adaptor to instantiate my fragment class.I am able to do so but my problem is that my getItem() method is getting called twice which is creating problem further.can u explain me why it is happening .

    package com.creatiosoft.rssfeed.adaptor;

    import android.content.Context;
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentPagerAdapter;
    import android.util.Log;

    import com.creatiosoft.rssfeed.utils.RssItem;
    import com.viewpagerindicator.IconPagerAdapter;

    public class NewsFeedsAdapter extends FragmentPagerAdapter implements
            IconPagerAdapter {

        int[] icon = null;
        String[] content = null;
        String[] URLs = null;
        Context cont;

        public NewsFeedsAdapter(FragmentManager fm, Context context) {
            super(fm);
            Log.i("jk", "constructor");
            this.cont = context;
            RssItem newsFeedAppliaction = (RssItem) cont;
            /*
             * Retrieving the values of the Icons and contents from the application
             * class in utils package
             */
            icon = newsFeedAppliaction.getICONS();
            content = newsFeedAppliaction.getCONTENT();
            URLs = newsFeedAppliaction.getURL();

        }

        /** instantiate a new fragment class */
        @Override
        public Fragment getItem(int position) {
            Log.i("yt", "hello" + position);
            return TestFragment.newInstance(position % content.length, cont);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return content[position % content.length].toUpperCase();
        }

        public int getIconResId(int index) {
            return icon[index];
        }

        /** return the no of views on the basis of array items */
        @Override
        public int getCount() {

            Log.i("hi", "length" + content.length);
            return content.length;
        }
    }      

I am calling Adaptor with this code:

NewsFeedsAdapter adapter = new NewsFeedsAdapter(
                getSupportFragmentManager(), getApplicationContext());
        /**
         * get the id of the view pager declared in the xml resource and set the
         * adaptor on the view pager
         */
        ViewPager pager = (ViewPager) findViewById(R.id.pager);
        pager.setAdapter(adapter);
        //pager.setCurrentItem(0);

        /**
         * Tab page indicator class is used to indicate the tabs and is accessed
         * from the library class
         */
        TabPageIndicator indicator = (TabPageIndicator) findViewById(R.id.indicator);
        indicator.setViewPager(pager);  

Upvotes: 6

Views: 5790

Answers (3)

Clean Devs
Clean Devs

Reputation: 269

The problem that you probably have is not the multiple calls of the method getItem(). After a little research, I found that the method isViewFromObject() has a huge role and in its documentation it is said that "This method is required for a PagerAdapter to function properly."

I also found that the right way to implement the method is this:

@Override
public boolean isViewFromObject(View view, Object object) {
    if(object != null){
        return ((Fragment)object).getView() == view;
    }else{
        return false;
    }
}

You can look here.

Upvotes: 0

gor
gor

Reputation: 1056

Be aware that the pager keeps at least one page ahead. Meaning that when the pager is created, he creates at least two pages - the one he shows and the next one, in order to allow "paging".

Upvotes: 12

ahodder
ahodder

Reputation: 11439

In your getItem method you create a new instance of a fragment. This is terrible. It puts you in the situation you are in now. What you are doing is creating an new annynmous item that will live out it days as you specified. But when the evil Android system decides that is needs to talk to your Fragment again and requests it from your adapter, you are telling it "No. I don't wanna!" and instead giving it a new fragment EXACTLY the same as its older rother.

To fix this, you inflate all of your fragment ahead of time and then return the proper fragment. Or if you rather, don't. But keep a record of the instances you have created so you may return already created fragments.

I don't know exactly why its being called twice - I haven't scoured v4's source, but it is probably done to ensure that the item is actually retrieved or the system entered a state where the previous item needed to be refereshed.

In conclusion, retain created instances -especially for object as heavy as fragments, views and activities.

class Adapter extends MyWhateverAdapter {
    Fragment[] myLovelyFragments;

    public Adapter() {
        // Instantiate your fragments and place them into myLovelyFragments
    }

    public int getFragmentCount() {
        return myLovelyFragments.length;
    }

    public Fragment getItem(int position) {
        return myLovelyFragments[position];
    }
}

Upvotes: 2

Related Questions