Viewpager getItem adapter is always called for index 0 and 1

I'm just wondering if the normal behavior of the viewpager and its adapter is always to call the getItem() method on index 0 and 1, even if I immediately set the current position.

Here is my code:

 mNewsPagerAdapter = new NewsDetailPagerAdapter(getChildFragmentManager()); mNewsPagerAdapter.updateNewsList(news); mViewPager = (ViewPager) mView.findViewById(R.id.horizontal_view_pager); mViewPager.setPageMargin(2); mViewPager.setPageMarginDrawable(R.color.black); mViewPager.setAdapter(mNewsPagerAdapter); mViewPager.setCurrentItem(mCurrentPositionPager, false); 

If I switch from my review activity to my activity using this viewpager , the adapter always calls the getItem() method for position 0 and 1, and then the getItem() method for mOriginalPosition and its neighbors. I was wondering if this behavior is correct, or if I missed something to implement it correctly. Thanks for the help:)

Edit: adapter code added

 public class NewsDetailPagerAdapter extends FragmentStatePagerAdapter { private SparseArray<Fragment> mPageReferenceMap = new SparseArray<Fragment>(); private ArrayList<News> mNewsList; public NewsDetailPagerAdapter(FragmentManager fm) { super(fm); } /** * Setzt die neuen News. **/ public void updateNewsList(ArrayList<News> list) { mNewsList = list; } @Override public Fragment getItem(int position) { Log.d("debug", "getItem position:" + position); News newsItem = mNewsList.get(position); NavigationFragment fragment = new NavigationFragment(); mPageReferenceMap.put(position, fragment); return fragment; } @Override public int getCount() { return mNewsList.size(); } @Override public int getItemPosition(Object object) { return POSITION_NONE; } public Fragment getFragment(int position) { return mPageReferenceMap.get(position); } 

}

+7
android adapter android-viewpager position
source share
4 answers

This is actually normal behavior. In fact, since you map the ViewPager to the adapter, the adapter creates the first visible layout (index 0), ending with the next (index 1). This is done by default in the "setAdapter". Then, when you set a different position, the adapter will create an instance of the fragment at the selected index, previous and next.

This is the usual setAdapter code for the ViewPager:

 public void setAdapter(PagerAdapter adapter) { if (mAdapter != null) { mAdapter.setViewPagerObserver(null); mAdapter.startUpdate(this); for (int i = 0; i < mItems.size(); i++) { final ItemInfo ii = mItems.get(i); mAdapter.destroyItem(this, ii.position, ii.object); } mAdapter.finishUpdate(this); mItems.clear(); removeNonDecorViews(); mCurItem = 0; scrollTo(0, 0); } final PagerAdapter oldAdapter = mAdapter; mAdapter = adapter; mExpectedAdapterCount = 0; if (mAdapter != null) { if (mObserver == null) { mObserver = new PagerObserver(); } mAdapter.setViewPagerObserver(mObserver); mPopulatePending = false; final boolean wasFirstLayout = mFirstLayout; mFirstLayout = true; mExpectedAdapterCount = mAdapter.getCount(); if (mRestoredCurItem >= 0) { mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); setCurrentItemInternal(mRestoredCurItem, false, true); mRestoredCurItem = -1; mRestoredAdapterState = null; mRestoredClassLoader = null; } else if (!wasFirstLayout) { populate(); } else { requestLayout(); } } if (mAdapterChangeListener != null && oldAdapter != adapter) { mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter); } } 

To change the behavior of the ViewPager, you can extend the classic ViewPager by overriding the setAdapter method and set mCurrItem to the desired position.

I hope this helps

Edit:

After various tests, we found a solution.

If the ViewPager adapter is installed after the ViewPager layout is visible, items 0 and 1 are loaded. If you want to avoid this behavior, but you cannot install the adapter before the layout becomes visible (because you are waiting for data), you can use this workaround:

1) First set the visibility of the ViewPager to GONE

2) After receiving all the data, you will update the adapter and set the current value of the element

3) Finally, you set the visibility of the ViewPager to VISIBLE

Here you can find an example:

 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.detail_overview_fragment, container, false); final int position = getArguments().getInt("position"); final ViewPager viewPager = (ViewPager) v.findViewById(R.id.viewpager); viewPager.setVisibility(View.GONE); Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { viewPager.setAdapter(new PagerAdapter(getChildFragmentManager())); viewPager.setCurrentItem(position); viewPager.setVisibility(View.VISIBLE); } },5000); return v; } 
+1
source share

Yes, this is normal ViewPager behavior, because it will always try to stay ahead of the user by rendering tabs that limit the drawing area. I personally do not recommend creating a custom ViewPager, as you almost certainly break functionality if you don’t know what you are doing. The adapter class should look something like this:

 public class YourCustomPagerAdapter extends FragmentStatePagerAdapter { private List<Fragment> fragmentList = new ArrayList<>(); private List<String> titleList = new ArrayList<>(); public WizardPagerAdapter(FragmentManager fm) { super(fm); } public void addFragment(Fragment fragment, String title) { fragmentList.add(fragment); titleList.add(title); } @Override public Fragment getItem(int position) { return fragmentList.get(position); } @Override public CharSequence getPageTitle(int position) { super.getPageTitle(position); return titleList.get(position); } @Override public int getCount() { return fragmentList.size(); } } 

and you should add your snippets as such:

  @Override public void onCreate(Bundle savedInstanceState) { ... YourCustomPagerAdapter adapter = new YourCustomPagerAdapter (getSupportFragmentManager()); adapter.addFragment(FragmentOne.newInstance(), "Frag 1"); adapter.addFragment(FragmentTwo.newInstance(), "Frag 2"); viewPager.setAdapter(adapter); ... } 
+2
source share

This is normal (and reasonable in my opinion). The ViewPager class has one property called mOffscreenPageLimit with a default value of 1. This number determines how many pages are left and right of the current page that the Viewpager will load. For example, you have 10 pages, the current position is 5, and mOffcreenPageLimit is 1, the page at positions 4 and 6 will be loaded.

You can change this property by calling this method

 viewpager. setOffscreenPageLimit(int) 

If you pass an integer less than 1, it will have no effect.

+2
source share

I think the error is the adapter:

  /** * Setzt die neuen News. **/ public void updateNewsList(ArrayList<News> list) { //mNewsList = list; mNewsList.clear(); mNewsList.addAll(list); /** * Notifies the attached observers that the underlying data has been changed * and any View reflecting the data set should refresh itself. */ this.notifyDataSetChanged(); } 

cause of error: this list is a distinctive entity for this adapter.

-one
source share

All Articles