I am using Android's support.v4
package to develop a ViewPager containing multiple Fragment
s.
I am trying to hide the Views when the user changes page. So, I implemented an OnPageChangeListener
to listen to my adapter, and call an update()
method in my Fragment
s when when a page change occurs. But I'm getting a NullPointerException
, and I cannot figure out why.
Here is the code:
public class MyActivity extends FragmentActivity implements
OnPageChangeListener {
private static final int NUM_ITEMS = 2;
private ViewPager mPager;
private static SpaceAdapter mAdapter;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_pager);
mAdapter = new SpaceAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mPager.setOnPageChangeListener(this);
}
public static class SpaceAdapter extends FragmentPagerAdapter {
public SpaceAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return NUM_ITEMS;
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new MyFragment();
case 1:
return new MyFragment();
default:
return new MyFragment();
}
}
}
@Override
public void onPageScrollStateChanged(int arg0) {
Log.i("pagination", "scroll state changed: " + arg0);
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// Log.i("pagination", "page scroll: " + arg0 + " with: " + arg1 + ", " + arg2);
if (mAdapter.getItem(arg0) instanceof IUpdateOnPage) {
((IUpdateOnPage) mAdapter.getItem(arg0)).updateOnPage();
}
}
@Override
public void onPageSelected(int arg0) {
Log.i("pagination", "page selected: " + arg0);
}
}
and
public class MyFragment extends Fragment implements
SurfaceHolder.Callback, IUpdateOnPage {
private SurfaceView charts;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.crew, null);
bindViews(v);
return v;
}
private void bindViews(View v) {
charts = (SurfaceView) v.findViewById(R.id.civ_charts);
charts.getHolder().addCallback(this);
Log.i("wtf", "huh " + String.valueOf(charts == null)); // logs false
}
@Override
public void updateOnPage() {
if (charts != null) {
Log.i("crew surface", "hidden");
charts.setVisibility(View.GONE);
} else {
Log.i("crew surface", "charts is null"); //THIS HERE gets logged
}
}
}
wWhen I copy/pasted I removed the SurfaceHolder.Callback
methods, but they are there. The bindViews(v)
method logs if charts == null
, and that always returns false. When I page, updateOnPage
gets called, and charts == null
returns true. Why does this happen and how do I get around it?
and this is line 108:
charts.setVisibility(View.GONE);
Using the ViewPager. OnPageChangeListener is the correct way to go, but you will need to refactor your adapter a bit in order to keep a reference to each Fragment contained in the FragmentPagerAdapter. Then, instead of creating a new Fragment, use the one contained in the adapter: mViewPager.
yes...you can use View instead of Fragment in viewpager.
ViewPager in Android is a class that allows the user to flip left and right through pages of data. This class provides the functionality to flip pages in app. It is a widget found in the support library. To use it you'll have to put the element inside your XML layout file that'll contain multiple child views.
Add the following when you initialize your ViewPager
,
mPager.setOffscreenPageLimit(NUM_ITEMS-1);
In your case, this will set the number of off-screen pages to 1 (i.e. it will keep the additional off-screen page in memory when the other page is currently in focus). This will force your ViewPager
to keep all of the Fragment
s even when they are not in focus.
I examined your code and I think the issue is that in onPageScrolled
, you're calling getItem
. This implementation (which is actually like most implementations of it on web) returns a new instance each time. However, most examples I've seen don't call getItem
, so this is usually alright.
In your case, I would hold lazily create the Fragment in getItem
: if it doesn't exist for that position, then create it, and then hang onto it in an ArrayList
or some other collection, but if it already exists, just return it from that collection.
Otherwise, you create a fragment instance A, then scroll to another fragment instance B. You try to tell fragment instance A to clean up some views, but you wind up telling a new fragment instance C to do so. It hasn't had a chance to set up its own views yet, so you're getting the null pointer to charts.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With