Java – NullPointerException when the viewpager is displayed for the second time
The viewpager clip I use has two clips for children This is great, but when I replace the viewpager fragment with another fragment and replace this fragment with the viewpager fragment, my application uses the following NullPointerException:
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.util.ArrayList.size()' on a null object reference at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:667) at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:211) at android.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:1319) at android.view.View.dispatchRestoreInstanceState(View.java:13756) at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2888) at android.view.View.restoreHierarchyState(View.java:13734) at android.support.v4.app.Fragment.restoreViewState(Fragment.java:468) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1094) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248) at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:738) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1613) at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:517) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5294) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)
My viewpager fragment contains the following source code to implement two sub fragments in case they are null In addition, the viewpageradapter implementation is instantiated and assigned to viewpager
public class ConnectionPasswordViewPagerFragment extends Fragment { private ViewPager vpConnectionPassword; private ConnectionPasswordViewPagerAdapter paConnectionPassword; private ConnectionPasswordGeneratorMACAddress passwordGeneratorMACAddress; private ConnectionPasswordGeneratorSerialNumber passwordGeneratorSerialNumber; public ConnectionPasswordViewPagerFragment() { // required empty public constructor } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if ((this.passwordGeneratorSerialNumber == null) && (this.passwordGeneratorMACAddress == null)) { this.passwordGeneratorMACAddress = new ConnectionPasswordGeneratorMACAddress(); this.passwordGeneratorSerialNumber = new ConnectionPasswordGeneratorSerialNumber(); } } @Override public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_connection_password_view_pager,container,false); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); /*if (this.paConnectionPassword == null) {*/ this.paConnectionPassword = new ConnectionPasswordViewPagerAdapter(this.getChildFragmentManager(),this.getActivity(),this.passwordGeneratorMACAddress,this.passwordGeneratorSerialNumber); //} this.vpConnectionPassword = (ViewPager) this.getActivity().findViewById(R.id.vpConnectionPassword); this.vpConnectionPassword.setAdapter(this.paConnectionPassword); } }
The viewpageradapter shown below will retain references to sub fragments in ArrayList and implement getitem(), getcount(), and getpagetitle() The viewpagerfragment class simply extends the support fragment class and provides an abstract method implemented by sub fragments, getpagetitlestringid()
public class ConnectionPasswordViewPagerAdapter extends FragmentStatePagerAdapter { private static final byte NUMBER_OF_FRAGMENTS = (byte) 2; private ArrayList<ViewPagerFragment> childFragments; private Activity displayActivity; public ConnectionPasswordViewPagerAdapter(FragmentManager fragmentMgm,Activity displayAct,ConnectionPasswordGeneratorMACAddress generatorMACAddress,ConnectionPasswordGeneratorSerialNumber generatorSerialNumber) { super(fragmentMgm); this.childFragments = new ArrayList<>(ConnectionPasswordViewPagerAdapter.NUMBER_OF_FRAGMENTS); this.setDisplayActivity(displayAct); if (generatorMACAddress != null) { this.childFragments.add(generatorMACAddress); } if (generatorSerialNumber != null) { this.childFragments.add(generatorSerialNumber); } } public Activity getDisplayActivity() { return this.displayActivity; } public void setDisplayActivity(Activity value) { this.displayActivity = value; } @Override public Fragment getItem(int position) { return this.childFragments.get(position); } @Override public int getCount() { return ConnectionPasswordViewPagerAdapter.NUMBER_OF_FRAGMENTS; } @Override public CharSequence getPageTitle(int position) { return this.getDisplayActivity().getString(this.childFragments.get(position).getPageTitleStringID()); } }
Thanks for your help!
Solution
I solved the problem by creating a fragment containing a view pager every time I called an alternative method that supports the fragment manager
public void onSwitchToConnectionPasswordGenerator(View clickedView) { this.fragConnectionPassword = new ConnectionPasswordViewPagerFragment(); this.getSupportFragmentManager().beginTransaction().replace(R.id.flFragmentContainer,this.fragConnectionPassword).commitAllowingStateLoss(); }