Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fragment without a view crashes on configuration change

Tags:

I have an UI where I need a Fragment to be displayed (with a view) in landscape mode but not in portrait mode. In portrait mode it should still be available but will display its result using ListPopupWindow instead.

I figured I could handle this by using the <fragment /> tag for the landscape layout while creating the fragment programmatically if it wasn't started (in the case when we are in portrait).

This works fine as long as you start out in landscape, if you start in portrait where the fragment is created programmatically your application will crash when you rotate the emulator when it tries to attach the fragment to your layout:

java.lang.IllegalStateException: Fragment did not create a view. at android.app.Activity.onCreateView(Activity.java:4095)

The docs for Fragment.isInLayout() seems to hint that it should be able to handle it this way:

Return true if the layout is included as part of an activity view hierarchy via the tag. This will always be true when fragments are created through the tag, except in the case where an old fragment is restored from a previous state and it does not appear in the layout of the current state.

So the question is how to do this correctly or if there is something I'm missing?

UPDATE:

Seems like isInLayout() isn't behaving as it should currently as well. It returns false if you have added a Fragment to a container manually.

Also, if you add a Fragment manually to a container and then rotate (the device) to a layout that does not contain that layout it will crash:

Caused by: java.lang.IllegalArgumentException: No view found for id 0x7f060011 for fragment SearchFragment{4042f868 #2 id=0x7f060011 SearchFragment} at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:722)

like image 750
alexanderblom Avatar asked Feb 08 '11 18:02

alexanderblom


1 Answers

Have you come up with an answer to this? I was having a similar problem, and managed to come up with a solution. You can easily do what you are attempting as follows:

Create two different layouts one in the layout directory, one in the layout-land directory. The one in the layout-land directory will be used in landscape mode. As a placeholder, where you want your fragment to go, use s FrameLayout element, and id it, say with the id "my_fragment". The layout in the layout directory should not contains any element with that id.

In your onCreate method, use findViewById(R.id.my_fragment) to locate the fragment placeholder. If it exists, you are in landscape mode and should add your fragment (if it does not exist already): add(R.id.my_fragment, new MyFragment, "myFragment). If you get null, you are in portrait mode and should not create the fragment.

Be very careful that you never replace a fragment created using a tag, with one that you create dynamically in your program. A fragment for which isInLayout returns true is a completely different beast, that one for which it returns false. Their lifecycles are entirely different. Replacing one with the other will lead to the dreaded IllegalStateException "Fragment did not create a view" problem.

-blake

like image 168
Blake Meike Avatar answered Oct 11 '22 07:10

Blake Meike