I have a simple Fragment with a ViewPager.
I'm using the up to date support library, v4 rev18!
If I show it the first time, everything works fine, if I go back and show it again, the app crashes with the following exception:
java.lang.NullPointerException
at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:569)
at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:211)
at android.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:1281)
at android.view.View.dispatchRestoreInstanceState(View.java:12043)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2688)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2694)
at android.view.View.restoreHierarchyState(View.java:12021)
at android.support.v4.app.Fragment.restoreViewState(Fragment.java:425)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:949)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1460)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4800)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:798)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:565)
at dalvik.system.NativeStart.main(Native Method)
My simple class looks like following and should be, actually, fine...
public class RoutineDayFragment extends BaseFragment
{
private RoutinesActivity mParent = null;
@InjectView(R.id.pager)
MyViewPager pager = null;
@InjectView(R.id.indicator)
PagerSlidingTabStrip indicator = null;
private FragmentStatePagerAdapter mAdapter = null;
@Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
mParent = ((RoutinesActivity) getBaseActivity());
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.view_pager, container, false);
Views.inject(this, v);
mAdapter = new FragmentStatePagerAdapter(getChildFragmentManager())
{
@Override
public int getCount()
{
if (mParent.getSharedData().selectedRoutine == -1)
return 0;
return mParent.getSharedData().routines.get(mParent.getSharedData().selectedRoutine).getRWorkoutDay().size();
}
@Override
public Fragment getItem(int pos)
{
return DayFragment.newInstance(pos);
}
@Override
public CharSequence getPageTitle(int pos)
{
return Common.getString(R.string.day) + (pos + 1);
}
};
pager.setAdapter(mAdapter);
indicator.setViewPager(pager);
return v;
}
}
Use an AsyncTask to set the ViewPagerAdapter:
private class SetAdapterTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
return null;
}
@Override
protected void onPostExecute(Void result) {
if(mAdapter != null) mViewPager.setAdapter(mAdapter);
}
}
Call it like this:
mAdapter = new PageAdapter(getChildFragmentManager());
new SetAdapterTask().execute();
And reset the adapter in the onResume(
) method of your Fragment.
Allright, here it is. I modified the Google example of Effective Navigation to fit your concerns.
What did I create?
Here is the Main Activity.java
It contains two adapters, one for the main Fragments, one for the sub Fragments. Furthermore, their are two Fragment classes, one is the Fragment containing the ViewPager (the main-Fragment), the other one is the sub-Fragment (inside the nested ViewPager)
public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
AppSectionsPagerAdapter mAppSectionsPagerAdapter;
NonSwipeableViewPager mViewPager;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAppSectionsPagerAdapter = new AppSectionsPagerAdapter(getSupportFragmentManager());
// Set up the action bar.
final ActionBar actionBar = getActionBar();
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Set up the ViewPager, attaching the adapter and setting up a listener for when the
// user swipes between sections.
mViewPager = (NonSwipeableViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mAppSectionsPagerAdapter);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
// For each of the sections in the app, add a tab to the action bar.
for (int i = 0; i < mAppSectionsPagerAdapter.getCount(); i++) {
actionBar.addTab(
actionBar.newTab()
.setText(mAppSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
@Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {}
@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {}
public static class AppSectionsPagerAdapter extends FragmentPagerAdapter {
public AppSectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int i) {
switch (i) {
default:
// The other sections of the app are dummy placeholders.
Fragment fragment = new ViewPagerContainerFragment();
return fragment;
}
}
@Override
public int getCount() {
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
return "Tab " + (position +1);
}
}
public static class ViewPagerAdapter extends FragmentPagerAdapter {
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int i) {
switch (i) {
default:
// The other sections of the app are dummy placeholders.
Fragment fragment = new ViewPagerFragment();
Bundle b = new Bundle();
b.putString("key", "I am fragment nr " + i);
fragment.setArguments(b);
return fragment;
}
}
@Override
public int getCount() {
return 10;
}
}
/**
* THIS FRAGMENT CONTAINS A VIEWPAGER
*/
public static class ViewPagerContainerFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.main_fragment, container, false);
ViewPager pager = (ViewPager) rootView.findViewById(R.id.nestedViewPager);
pager.setAdapter(new ViewPagerAdapter(getChildFragmentManager()));
return rootView;
}
}
/**
* THIS FRAGMENT IS INSIDE THE VIEWPAGER
*/
public static class ViewPagerFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.sub_fragment, container, false);
((TextView) rootView.findViewById(R.id.tv1)).setText(getArguments().getString("key"));
((TextView) rootView.findViewById(R.id.tv1)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(), CollectionDemoActivity.class);
startActivity(intent);
}
});
return rootView;
}
}
}
activity_main.xml
<com.example.android.effectivenavigation.NonSwipeableViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
main_fragment.xml
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/nestedViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="24sp" />
sub_fragment.xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="50sp" />
The end result looks like this:
We have 3 top-level Fragments each containing a ViewPager with 10 Fragments.
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