FragmentStatePagerAdapter handling getItem() position
Asked Answered
S

4

3

I tried this, but wrong lists get binded to the recyclerview. I tried SparseArray as well, even that doesn't work. getItem() gets called twice when i start Mainactivity. How do I handle the position returned? I tried returning viewpager currentItem, even that doesn't work.

MainActivity

public class PagerAdapter extends FragmentStatePagerAdapter {
    int mNumOfTabs;


    public PagerAdapter(android.support.v4.app.FragmentManager fragmentManager, int tabCount) 
    {
        super(fragmentManager);
        this.mNumOfTabs = tabCount;    
    } 

    @Override
    public Fragment getItem(int position) {

        return Categories_Fragment.newInstance(position);

    }

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

}

Categories_Fragment

public class Categories_Fragment extends Fragment 
{
private RecyclerView lvMessages; 
private int fromPage;


public static Categories_Fragment newInstance(int num) {
    Categories_Fragment f = new Categories_Fragment();

    // Supply num input as an argument.
    Bundle args = new Bundle();
    args.putInt("from", num);
    f.setArguments(args);

    return f; 
}


@Override
public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    fromPage = getArguments().getInt("from"); 


}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {      
    // TODO Auto-generated method stub  
    View rootView = inflater.inflate(R.layout.categories_filter, container, false); 
    lvMessages    = (RecyclerView)rootView.findViewById(R.id.lv_categories_filter);

    LinearLayoutManager x =  new LinearLayoutManager(getActivity()); 
    x.setOrientation(LinearLayoutManager.VERTICAL); 

    lvMessages.setLayoutManager(x);   


    return rootView; 
}


@Override
public void onActivityCreated(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onActivityCreated(savedInstanceState);

    // bind different data to the RecyclerView based on fromPage value. 

    }

}
Stator answered 14/11, 2015 at 8:15 Comment(3)
try to set your Fragment to static: public static class Categories_Fragment extends FragmentBoltzmann
Please post code where it is referencing PagerAdapter. I think the main problem is "getItem() gets called twice..."Housel
This should work for you. Implement a interface that gets called only when the fragment is visible. https://mcmap.net/q/373564/-how-to-handle-asynctask-39-s-in-actionbaractivity-fragments-when-viewpager-is-usedDidactics
C
2

Here's what may be the kicker...

@Override
public void setUserVisibleHint(boolean isVisible) {
    super.setUserVisibleHint(isVisible);
    if (isVisible) {
        // bind to stuff using value of fromPage from here
    }
}

public void setUserVisibleHint (boolean isVisibleToUser): Set a hint to the system about whether this fragment's UI is currently visible to the user. This hint defaults to true and is persistent across fragment instance state save and restore.

What might be the problem (if I'm understanding your question correctly) is the pager is passing along its "last known" position, which doesn't necessarily mean is the position of the fragment that is currently being displayed on the device screen.

UPDATE: here's a complete example with a ViewPager handling the same fragment but with different data passed to it:

public class ViewPagerAdapter extends FragmentStatePagerAdapter {

    private JSONArray itemsArray;
    private int fragmentId;

    public ViewPagerAdapter(JSONArray itemsArray, int fragmentId, FragmentManager manager) {
        super(manager);
        this.itemsArray = itemsArray;
        this.fragmentId = fragmentId;
    }

    @Override
    public Fragment getItem(int position) {
        JSONObject itemObject = new Listing(itemsArray, position).getObject();
        Bundle bundle = new Bundle();
        bundle.putString("item_object", itemObject.toString());
        bundle.putInt("item_position", position);
        bundle.putInt("total_items", getCount());
        bundle.putInt("fragment_Id", fragmentId);
        Fragment fragment = new ListingFragment();
        fragment.setArguments(bundle);
        return fragment;
    }

    @Override
    public int getCount() {
        return itemsArray.length();
    }

}

Here's the Listings fragment (minus unimportant bits):

public class ListingFragment extends Fragment {

    private Listing listing;

    private String itemObject;
    private int itemPosition;
    private int totalItems;
    private int fragmentId;

    public ListingFragment() { }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle bundle = getArguments();
        itemObject = bundle.getString("item_object");
        itemPosition = bundle.getInt("item_position");
        totalItems = bundle.getInt("total_items");
        fragmentId = bundle.getInt("fragment_Id");
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
        View view = ...
        // nothing special to see here, just the usual stuff
        return view;
    }

    @Override
    public void setUserVisibleHint(boolean isVisible) {
        super.setUserVisibleHint(isVisible);
        if (isVisible) {
            // send fragmentID to wherever you want to use it
            // such as your recyclerview/adapter from here
         }
     }

}

I hope the example sheds some light, I know it works for me without fail.

Chafe answered 18/11, 2015 at 21:57 Comment(7)
I think this would work if i have different kind of fragments. But I'm using a single fragment with arguments passed to it.Stator
It should work with single fragments. I had the exact same problem with an app that fetched news headlines: each fragment was identical, containing a recyclerview, but the headlines shown differed, based on the category ID I passed within setUserVisibleHint(). If I passed the ID from getItem(), the fragment loaded items from the next category (or previous one, depending on which way I was swiping), because the ID it held was the last one that got cached in the pager, not the ID of the currently visible fragment.Chafe
Neil Agarwal's answer below explains the multiple getItem() calls by the way, because the pager is fetching the currently visible fragment as well as the one after it.Chafe
Could you please paste a little bit of code by updating your answer.Stator
Sure, just hang on a bit... ;)Chafe
I'm binding data as you suggested, but the first time, setUserVisibleHint() is called before onCreateView(), how do I get around this??Stator
Yes, why would it be a problem? It'll only return true for the fragment that's visible and get whatever data that that fragment has already set.Chafe
H
0

It is suspicious that you created a class called PagerAdapter, which is an Android abstract class. Rename it to a unique name like MyPagerAdapter.

Housel answered 20/11, 2015 at 8:31 Comment(1)
@Anirudh, Is it still calling getItem() twice? or, none at all?Housel
P
0

The reason why the getItem() is called twice is because of the default value assigned to offScreenPageLimit in ViewPager.

you can set the offScreenPageLimit to 1 or 0 using setOffscreenPageLimit (int limit) method of ViewPager class, and this will solve your problem of calling getItem() twice.

Hence, if getItem() is called once, then you will get the correct position value in the fragment and your problem wil lbe resolved.

checkout the link for method definition and description

http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit(int)

Protraction answered 20/11, 2015 at 12:40 Comment(1)
Tried this even before posting the question. Doesn't work for me.Stator
F
0

Using FragmentStatePagerAdapter ,HashMap<Integer,Demo_Fragment>

 public class ViewPagerAdapter extends FragmentStatePagerAdapter {
        List<String> mList;

        public ViewPagerAdapter(FragmentManager fm, List<String> list) {
            super(fm);
            mList = list;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            String  title = mList.get(position);
            return title;
        }

        public int getCount() {
            return mList.size();
        }

        public Fragment getItem(int position) {
            Demo_Fragment fragment = new Demo_Fragment();
            Bundle bundle = new Bundle();
            bundle.putString("text",mList.get(position));
            fragment.setArguments(bundle);
            fragment.setTags(position);
            mPageReferenceMap.put(position, fragment);

            return fragment;
        }

        public void destroyItem(ViewGroup container, int position, Object object) {
            super.destroyItem(container, position, object);
            mPageReferenceMap.remove(position);
        }

        public int getItemPosition(Object item) {
            Demo_Fragment fragment = (Demo_Fragment) item;
            int position = fragment.getTags();
            if (position >= 0) {
                return position;
            } else {
                return POSITION_NONE;
            }
        }
    }

For get Fragment

public Demo_Fragment getFragment(int key) {
        return mPageReferenceMap.get(key);
    }

For get current Fragment in addOnPageChangeListener ViewPager

mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            }

            @Override
            public void onPageSelected(int position) {
                final Demo_Fragment demo_Fragment = getFragment(mViewPager.getCurrentItem());
                final String str = mArrString.get(mViewPager.getCurrentItem());
                demo_Fragment.updateView(str);
                showDialog();
                mRunnable = new Runnable() {
                    @Override
                    public void run() {
                        randomGenerator = new Random();
                        randomInt = randomGenerator.nextInt(10000);
                        demo_Fragment.updateView(str +"\n" +randomInt+"-Updated Value");
                        hideDialog();
                    }
                };
                mHandler.postDelayed(mRunnable, 2000);


            }

            @Override
            public void onPageScrollStateChanged(int state) {
            }
        });

Working example - Click Here

Fester answered 23/11, 2015 at 6:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.