Reputation: 695
I want to have a paged layout where each page is a fragment with a list of items. The data comes from a web service in a single call and will be separated (say, by keyword) into one or more of the lists.
My attempt was to use a ViewPager and created a "Manager":
class PagesManager extends FragmentPagerAdapter
which has a list of (array) adapters and a list of fragments. Fragments are instances of:
class Page extends SherlockListFragment implements OnScrollListener
with a constructor:
public Page(PagesManager manager, int id)
which of courses causes a FragmentInstantiationException; I can pass the reference and id to the page in some other ways and leave an empty constructor, but the lists aren't redrawn even if I call notifyDataSetChanged() on the adapters. So my question is, how can I have multiple instances of the same Fragment class (the number of pages in the ViewPager needs to be customizable) that have different properties be able to restore their configuration after the system reinstantiates them? I realize this may be too general, but I feel that my issue is design, I do have the code which works fine except after the fragments are destroyed on rotate or if the app is in the background too long.
EDIT This is the adapter:
public class DiscoverListAdapter extends ArrayAdapter<String> {
private final Context context;
private DiscoverPagesManager manager;
private int id;
public DiscoverListAdapter(Context context, DiscoverPagesManager manager, int id) {
super(context, R.layout.note_item);
this.context = context;
this.manager = manager;
this.id = id;
}
@Override
public int getCount() {
return manager.pageGetCount(id);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// load up the stuff
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.note_item, parent, false);
// now fill it up
Note note = manager.pageGetNote(id, position);
((TextView) rowView.findViewById(R.id.note_item_displayname))
.setText(note.getUser().getUsername());
return rowView;
}
}
I create the fragments in the manager:
public DiscoverPagesManager(Context context, FragmentManager fm) {
super(fm);
pages = new ArrayList<Fragment>();
pages.add( new SearchPage() );
adapters = new ArrayList<DiscoverListAdapter>();
adapters.add(null);
notes = new ArrayList<List<Note>>();
notes.add(null);
DiscoverPage page;
for(int i=1; i<titles.length; i+=1) {
page = new DiscoverPage(this, i);
this.pages.add( page );
this.adapters.add( new DiscoverListAdapter(context, this, i) );
this.notes.add(null);
}
and
@Override
public Fragment getItem(int position) {
return this.pages.get(position);
}
Upvotes: 0
Views: 112
Reputation: 33741
I think you're doing this wrong. You need to think about the FragmentPagerAdapter as doing one thing and one thing only: managing the handling of Fragments as pages. Now, it happens to be that the Fragments that you're adding to the Fragment adapter have, themselves, adapters that handle the data inside of them, but that doesn't mean those concerns should intersect at all. You simply need to add Fragments to your FragmentPagerAdapter. Then, inside of your ListFragments, those will be backed by their own adapter. In other words, managing an ArrayList<DiscoverListAdapter>()
inside of the PagerAdapter is a big no-no. The DiscoverListAdapter should be created inside of either onCreate on onCreateView of the individual Fragments.
EDIT:
getItem in the FragmentPagerAdapter passes the position in the adapter to you. What you need is to have the bind that data to the Fragment. Use a simple, clean pattern like this:
public class MyFragment extends Fragment {
private int mPosition;
public static MyFragment newInstance(int position) {
MyFragment fragment = new MyFragment();
Bundle bundle = new Bundle();
bundle.putInt("position", position);
fragment.setArguments(bundle);
return fragment;
}
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
Bundle data = getArguments();
mPosition = data.getInt("position");
//do something based on position
}
}
//in your PagerAdapter:
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(position);
}
Upvotes: 1