I'm using ViewPager and FragmentPagerAdapter within a detail-view. This means I have a list of items and one screen shows the details of a single item. But the user can swipe left and right to navigate through all items. This follows the Google guideline for swiping views.
But I wonder about one thing. Within a ListView the views for each row get re-used. Once a row scrolls out of the screen it is re-used as the convertView parameter of the getView method of the adapter that is bound to the ListView. But this re-usage behavior does not seem to be implemented for swiping views. This example illustrates this:
class DemoAdapter extends ArrayAdapter<DemoItem> {
public DemoAdapter(Context context, List<DemoItem> objects) {
super(context, 0, objects);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
// create a new view, otherwise re-use the existing convertView
LayoutInflater i = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = i.inflate(R.layout.list_item_demo, parent, false);
}
// get current item
DemoItem item = getItem(position);
if (item == null)
return convertView;
// update view with the item
TextView textTitle = (TextView)convertView.findViewById(R.id.demo_title);
if (textTitle != null)
textTitle.setText(item.getTitle());
return convertView;
}
}
But here's the problem: Both, the FragmentPagerAdapter and the FragmentStatePagerAdapter are creating the fragments (each screen is a fragment) in their getItem method. But they don't get old fragments as an input parameter. The only difference is, that the FragmentStatePagerAdapter destroys unused fragments.
public class DemoItemsPagerAdapter extends FragmentPagerAdapter {
private final Context context;
public DemoItemsPagerAdapter(FragmentManager fm, Context context) {
super(fm);
this.context = context;
// ToDo: get cursor or array of available items that can be swiped through
}
@Override
public Fragment getItem(int i) {
Fragment fragment = new DemoItemFragment();
// ToDo: initialize fragment by correct item
// ToDo: avoid creating too many fragments - try reusing them (but how?)
return fragment;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
// the container is not the fragment, but the ViewPager itself
return super.instantiateItem(container, position);
}
@Override
public CharSequence getPageTitle(int position) {
// ToDo: return name for current entry
return null;
}
@Override
public int getCount() {
// ToDo: get count from cursor/array of available items
return 2;
}
}
So, how can I reuse the fragments? Actually getItems should only be called twice because there is only one fragment visible at a time and a second one once the transition starts while the user is swiping.
UPDATE: Because of confusion, I created this drawing. It shows the behavior of the adapters. The default one keeps all fragments in memory unless the device runs out of memory. One the app is in background or killed and then restored each fragment will be restored from its SavedInstanceState. The second implementation keeps only some fragments in memory but if you swipe left/right the destroyed ones will be completely created again from scratch. The third implementation is what I'm seeking. You have only three fragments which are then reused when swiping left or right. So fragment A can be position 1, 2, 3, 4, 5, 6 and 7.