In my small Android app, I have a ViewPager with 3 pages, each page contains one fragment, that's all working fine with a FragmentStatePagerAdapter (see earlier question).
Now for larger screens, I would like to keep a ViewPager, but I want the first two fragments to be on the same first page.
For this, I implement my own PagerAdapter and this is mostly working, the only problem I am trying to resolve is when I am rotating the screen, I get an error:
12-11 16:34:13.526: ERROR/AndroidRuntime(9221): FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.matthieu/com.matthieu.TestActivity}: java.lang.IllegalArgumentException: No view found for id 0x7f030002 (com.matthieu:id/top_fragment) for fragment TestFragment{481a3a98 #0 id=0x7f030002}
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3815)
at android.app.ActivityThread.access$2400(ActivityThread.java:125)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2037)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4627)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:871)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalArgumentException: No view found for id 0x7f030002 (com.matthieu:id/top_fragment) for fragment TestFragment{481a3a98 #0 id=0x7f030002}
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:903)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1070)
at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1861)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:547)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1129)
at android.app.Activity.performStart(Activity.java:3781)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2636)
... 12 more
I put a sample code simulating what I am trying to do (and showing this error message) on GitHub.
I guess one problem I have is because of the Fragments I have in the real application, I cannot really have a static newInstance constructor, but instead the Fragments are created ahead of time and have 'setRetainInstance(true);' set.
I understand the id of the viewGroup that will contain the fragment should be part of the hierarchy, and eventually, I guess, it is...
If it makes any difference, I am using the support library and the SherlockActionBar to maintain backwards compatibility with older devices.
Any idea on how to go about this?
EDIT: I have found that if I remove the Fragments from the FragmentManager in onSaveInstanceState I am not getting any crash anymore. All the fragments are recreated from scratch which is not what I want, but I guess I might have to do this and somehow recover those fragments later....
All right, even though I moved to another way of doing things, I don't like to leave things incomplete...
Going the way of the nested Fragments as suggested by Mark. The link posted in the comments goes to 404, but I found your example code about nested fragments.
A few things I've learned on the way:
Nested fragments cannot have setRetainInstance(true), or it will get:
java.lang.IllegalStateException: Can't retain fragements that are nested in other fragments
It was a mistake to create a FrameLayout in the page of the ViewPager to hold the fragment. Looking in the Android code (and specifically the FragmentPagerAdapter), I should just use container.getId() to find where to add the Fragment. Looks like you cannot do anything more sophisticated at that level or it will break.
From my understanding, if the fragments hold some information (like I do) that takes a long time to load, the different ways to handle this are:
onSaveInstanceState (preferred way ?), but not possible if the Fragment is nested. The (empty) constructor will get called when needed by the framework.setRetainInstance(true), in that case savedInstanceBundle is always null, but that Fragment (as Java object) will not be destroyed and it will still go through onAttach / onCreateView.Anyway, I pushed my solution using nested fragments on github
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