FragmentPagerAdapter and FragmentStatePagerAdapter

I am currently thinking which implementation of the PagerAdapter I should use. I have dilemmas related to both of them. Let me show you what it is.

1 # FragmentPagerAdapter

It works great. It creates new fragments instances when none of the previous instances is available, and retrieves fragments earlier, when possible.

Recently I read an article about StackOverflow, the method of PagerAdapter's getItem() method is called ONLY when it needs to create a fragment, but - it is called again and again, and I had to process the creation of new instances and retrieve the old ones inside this body method.

BUT - Only a few callback and lifecycle methods are called. For example, I cannot make an onSaveInstanceState call to call. Thus, there is no way to preserve the state of the fragment - of course, I can use SharedPreferences or something else, but I wanted to use callback methods. Is there any way to do this?

2 # FragmentStatePagerAdapter

Works fine, saves the state of each fragment that has a ViewPager .

BUT - this PagerAdapter ALWAYS creates a new fragment. I checked it inside the constructor.

Is it inefficient? I saw Romain Guy in Google I / O, saying that creating a new Views inefficient, especially when we create many Views , like in a ListView , so we use convertView to extract the existing View and change it for our purposes as many times as we want . So turning between pages is pretty similar - a lot of new Views - because a fragment is a kind of View

In both PagerAdapters I tried the trick with the Overriding destroyItem() method, but it did not work at all.

And here is my question.

What should I do?

Should I use SharedPreferences and option # 1 with FragmentPagerAdapter or option # 2 with FragmentStatePagerAdapter ?

Is there any possibility that I am doing something wrong with these adapters, do they behave differently from what we expect?

Below, my code is divided into readable parts.

PagerAdapter Part Part 1:

 /** * Adapter class to {@link WizardPager} */ public static class WizardCrazyAdapter extends FragmentStatePagerAdapter implements OnPageChangeListener{ public static final String tag = "android:switcher:"+R.id.pager_w+":"; /** * Refernece to root activity */ WizardActivity wizardActivity; /** * list of fragments */ private final ArrayList<FragmentInfo> fInfos = new ArrayList<FragmentInfo>(); private short prevPageNumber = 0; /** * Constructor of adapter * @param wizardActivity * {@link WizardActivity} as reference to activity root */ public WizardCrazyAdapter(WizardActivity wizardActivity) { super(wizardActivity.getSupportFragmentManager()); this.wizardActivity = wizardActivity; } static final class FragmentInfo { private final Class<?> _clss; private Bundle _args; public FragmentInfo(Class<?> clss, Bundle args) { _clss =clss; _args =args; } } public void addPage(Class<?> clss, Bundle args){ FragmentInfo fi = new FragmentInfo(clss, args); fInfos.add(fi); } /** * Return number of pages */ public int getCount() { return fInfos.size(); } 

PagerAdapter Part Part 2:

  /** * Searches in {@link FragmentManager} for {@link Fragment} at specified position * @param position * @return */ private AbstractWizardFragment getFragmentAt(int position){ FragmentManager fm = wizardActivity.getSupportFragmentManager(); AbstractWizardFragment awf = (AbstractWizardFragment) fm.findFragmentByTag(tag+position); return awf; } /** * Return page of view pager */ @Override public Fragment getItem(int position) { /*finding existing instance of fragment*/ AbstractWizardFragment awf = getFragmentAt(position); if(awf == null){ /*creating new instance if no instance exist*/ Log.v("WizardActivity", "creating new Fragment"); FragmentInfo fi = fInfos.get(position); awf = (AbstractWizardFragment) Fragment.instantiate(wizardActivity, fi._clss.getName()); }else{ Log.v("WizardActivity", "found existing Fragment"); } return awf; } 

Part PagerAdapter No. 3:

  @Override public void onPageSelected(int pageNumber) { wizardActivity.stepFragment.setCurrentStepAndChangeText(pageNumber); if(pageNumber != prevPageNumber){ AbstractWizardFragment prevFragment = (AbstractWizardFragment) getItem(prevPageNumber);//TODO change if any problems prevFragment.onDetachedFromViewPager(wizardActivity.mForm); } AbstractWizardFragment currFragment = (AbstractWizardFragment) getItem(pageNumber);//TODO change if any problems currFragment.onAttachedToViewPager(wizardActivity.mForm); prevPageNumber = (short) pageNumber; Log.d("WizardActivity", "onPageSelected"); } @Override public Object instantiateItem(ViewGroup arg0, int arg1) { Log.d("WizardActivity", "instantiateItem "+arg1); return super.instantiateItem(arg0, arg1); } @Override public void destroyItem(ViewGroup container, int position, Object object) { // super.destroyItem(container, position, object); Log.v("WizardActivity", "that would be destroy"); } } 

ViewPager Code:

 public class WizardPager extends ViewPager{ /** * Flag to check if view pager must be scrolled */ protected boolean isScrollable; /** * Default constructor * @param context {@link Context} */ public WizardPager(Context context) { super(context); isScrollable = true; } /** * Standard constructor * @param context {@link Context} * @param attrs {@link AttributeSet} */ public WizardPager(Context context, AttributeSet attrs) { super(context, attrs); isScrollable = true; } @Override public boolean onTouchEvent(MotionEvent event) { if (this.isScrollable) { return super.onTouchEvent(event); } return false; } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (this.isScrollable) { return super.onInterceptTouchEvent(event); } return false; } /** * Enable scroll of pages */ public void enableScroll(){ this.isScrollable = true; } /** * Disable scroll of pages */ public void disableScroll(){ this.isScrollable = false; } /** * Check if pages can be scrolled * @return */ public boolean isScrollable(){ return isScrollable; } } 
+4
source share
1 answer

I messed up with onPageSelectedMethod - I got FragmentStatePagerAdapter to call getItem - which instantly generates a fragment at least once - the method whenever the page changes. That's why I complained about creating an instance of Fragment every time the page was resized :)

Instead of getItem() I have to call my getFragmentAt() method getFragmentAt() , and the whole callback should look like this.

 @Override public void onPageSelected(int pageNumber) { wizardActivity.stepFragment.setCurrentStepAndChangeText(pageNumber); if(pageNumber != prevPageNumber){ AbstractWizardFragment prevFragment = (AbstractWizardFragment) getFragmentAt(prevPageNumber); prevFragment.onDetachedFromViewPager(wizardActivity.mForm); } AbstractWizardFragment currFragment = (AbstractWizardFragment) getFragmentAt(pageNumber); currFragment.onAttachedToViewPager(wizardActivity.mForm); prevPageNumber = (short) pageNumber; Log.d("WizardActivity", "onPageSelected"); } 

Although it works great. There may still be a risk that the Fragment will not be found and the method will return null - and therefore the NPE will be thrown.

+4
source

Source: https://habr.com/ru/post/1481273/


All Articles