We have an activity that displays data in a ViewPager.
This data has been pre-fetched from a remote database and is held in a separate singleton class.
That class supplies the following actions:
- Fetch and store initial data
- Fetch more data and add to the current list of data
- An Interface that allow the "caller" to know when data has been fetched.
The ViewPager then accesses this data and displays it.
What I am trying to do is to pre-load a certain number of entries (50) and display them. Then, when the used attempts to page to entry 51 I want to go and fetch more data.
So far, I have managed to get it to call the fetch code when needed but I can't seem to be able to get the pages to refresh. The ViewPager doesn't seem to know that more data is available. I have tried to do this by catching the scroll in onPageScrollStateChanged and, if it is the last entry, I get more data. The extra data is fetched in an async thread but a timer is shown that prevents user interaction while the data is being fetched.
I've tried removing and re-attaching the adapter, tried using notifyDataSetChanged() and tried returning POSITION_NONE in getItemPosition.
Sometimes it fails to update the screen at all whilst at other times I get an exception: "Fragment is not currently in FragmentManager".
This is my main class which, as can be seen, include two subclass - the adapter and the actual fragment.
public abstract class SwipeableDetailsScreen extends ContentScreen {
// ******** SwipeableFragment - Start ****************
protected abstract class SwipeableFragment extends Fragment{
/**
* Prints the details of the selected item to the screen
* @param contentView
*
* @param selectedItem An object containing data about the selected searchable from the ListView of SearchableListScreen
*
* Note. This method is NOT executed when the object is instantiated. It is executed when the screen is being prepared for display.
*/
public abstract void setSelectedItemDetails(ViewGroup contentView, Searchable selectedItem);
private Searchable _selectedItem;
public SwipeableFragment(Searchable selectedItem){
_selectedItem = selectedItem;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.searchable_details_screen, container, false);
// Set the data for the selected Searchable in the appropriate TextViews of this screen:
this.setSelectedItemDetails(contentView, _selectedItem);
return root;
}
protected abstract int getLayoutId();
}
// ******** SwipeableFragment - End ****************
// ******** SwipeableFragmentAdapter - Start ****************
protected abstract class SwipeableFragmentAdapter extends android.support.v13.app.FragmentStatePagerAdapter implements IconPagerAdapter, OnPageChangeListener {
private ViewPager _pager;
private boolean _needToGetMoreData = false;
public SwipeableFragmentAdapter(FragmentManager fragmentManager, ViewPager pager) {
super(fragmentManager);
_pager = pager;
_pager.setOnPageChangeListener(this);
}
@Override
public Fragment getItem(int position){
Fragment fragment;
if (position == 0){
_needToGetMoreData = true;
fragment = getFragment(null);
}
else{
_needToGetMoreData = false;
fragment = getFragment((Searchable) items[items.length-position-1]);
}
return fragment;
};
public abstract Fragment getFragment(Searchable item);
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
@Override
public int getCount() {
return items.length;
}
protected abstract CharSequence getName(int position);
@Override
public final CharSequence getPageTitle(int position){
CharSequence title = getName(position);
int currentPosition = _pager.getCurrentItem();
if (position < currentPosition)
title = title + " > ";
else if (position > currentPosition)
title = " < " + title;
return title;
}
public void setCount(int count) {
}
@Override
public int getIconResId(int index) {
// TODO Auto-generated method stub
return 0;
}
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_DRAGGING){
if (_needToGetMoreData){
ListResults.getInstance()
.addlistener(new ConnectionFinishedListener(){
@Override
public void connectionFinished(boolean error, boolean haveData, boolean lastChunk) {
// SwipeableFragmentAdapter.this.notifyDataSetChanged();
// SwipeableFragmentAdapter.this._pager.setAdapter(null);
SwipeableFragmentAdapter.this._pager.setAdapter(SwipeableFragmentAdapter.this);
}})
.getMoreData();
}
}
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
@Override
public void onPageSelected(int arg0) {
// TODO Auto-generated method stub
}
}
// ******** SwipeableFragmentAdapter - End ****************
// ******** Outer Class Methods ************
@Override
public void onCreate(Bundle savedInstanceState) {
// The super.onCreate() call will set the general frame also for this Screen:
super.onCreate(savedInstanceState);
// Read the details from the calling (previous) Activity and determine the layout for this screen:
Bundle bundle = getIntent().getExtras();
int currentItem = bundle.getInt(ListScreen.SELECTED_ITEM_POSITION,0);
// Add the content of this specific screen to the ScrollView:
ViewPager pager = (ViewPager) stb.findViewById(R.id.pager);
pager.setAdapter(getPagerAdapter(pager));
pager.setCurrentItem(items.length - currentItem - 1);
}
protected abstract SwipeableFragmentAdapter getPagerAdapter(ViewPager pager);
}
This class and its subclasses are then extended in order to supply screen-specific data.
The important point is that I do not want to fetch data unless I have to. In other words, I cannot pre-fetch data when the user is "approaching" the last entry. I must fetch the data ONLY when the user is trying to see the entry after the last one already fetched.
0 comments:
Post a Comment