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)
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
Your problem can also be due to not having a lanscape layout for the fragment you are using. You might have one for the portrait and so your program runs fine but when you rotate your device, the OS probably looks for the view in the landscape folder and doesnt find the view so declares it as missing. Check that you have view both in the folder "layout" and "layout-land".
Related
I have a fragment in which, when in landscape mode need to show another layout, while in portrait another layout?
Is there any way to achieve this behaviour?
My requirement is my bottom menu should be locked in portrait even when the orientation changes.
As my center view has been rotated, others are not changed.
Is it possible in android, if yes, how to implement it?
In your res folder, create layout-land folder. Create an xml layout file with the same name as the layout you are currently using for your fragment. In the newly created layout file, define your landscape layout.
I am beginner to android..I am started new android project..for supporting
different screen size..in fragment documentation they given to use fragment..but
why cant i use activity in android..if i use activity or fragment..which i should i use in this both..please dont give link of activity or fragment..please anyone answer me..i dont know which to use?...i want about all documentation they given about activity and fragment but i dint understand which to use..below is the link i read about fragment..if i use activity i should do more codings?
https://developer.android.com/guide/components/fragments.html
In fact you can't use a Fragment alone, Fragments are inside the Activity.
One point of using the Fragments for supporting different screen sizes is the ability to implement some views like a "Master/Detail" view.
A Fragment, as its name says, is a part of a bigger controller "the Activity", its reference can be removed and it's cleaner than having a big massive Activity to handle all the states of a view.
So the use case is completely depends on your project and its User Interface. I'd be glad to help you if you give me more information about your project and its design.
I think you will need at least one activity. And then for better handling different device rotations and screen sizes you can use one or more fragments inside this activity.
I try to explain this with an example:
You want to create a nice music player app which should look nice in portrait and landscape mode.
You split your app up into three fragments:
Here you can see how the app looks in portrait mode. The activity shows two fragments: The first fragment only consists of a listview. There the song titles are listed. On the bottom you can see the second fragment, which displays the song title of the current playing song and got a button for pausing the music.
When your user uses the music player app on a tablet in landscape mode you have more space for displaying stuff. Then the activity shows the list fragment (which also gets displayed in portrait mode) and it shows a third fragment which shows detailed information about the current playing song (e.g. the album image) and a progress bar.
By using fragments you only need to write the code for the list once.
Sweet and Simple thing, What i recommend is always use Fragments,
But for Fragment you will require Activity.
Take it in this way , Activity is a Canvas on which you can put any number of Fragments.
Whatever your UI is always use Fragment present on a activity if you want to show one screen even then also, So that you will always have Flexibilty to use all those cool things which fragments provides,maybe in future or in current.
If you use activity it has limits,FOR EXAMPLE, LIKE in INSTAGRAM AT BOTTOM, It has FIVE OPTIONS, Suppose THOSE OPTIONS ARE ON A ACTIVITY AND BY CLICKING ON THEM YOU CAN SWITCH TO DIFFERENT FRAGMENTS.
For more info:
Here is the most accepted answer for this topic.
My main xml file has a FrameLayout, with one fragment defined in the XML. At runtime, I am adding another fragment on top of this, and then a third fragment on top of this. When I add the runtime fragments, I don't give containerIds to attach them to. This is all fine until the orientation changes. After the orientation change, the third fragment has gone beneath the second fragment. But obviously I want the z-order to stay how it was before the orientation change, i.e. the last fragment added should be on top and visible.
I've tried using containerIds when adding the fragments, and adding them to the FrameLayout defined in XML, but when I put in containerIds, the runtime fragments simply don't show up at all.
So I'm wondering why the fragments added at runtime don't show when I use a containerId. Is it because they are being added to a container which already contains a fragment (the one defined in XML)? How can I get around this? I've tried adding additional containers to the XML to hold the runtime fragments, but this doesn't seem to work. The only way to get the fragments to show is to remove the containerId from the call to FragmentTransaction.add().
Also, is it possible to change the z-order of fragments manually? I've searched Google quite a lot to find this out and haven't found any answers. I've tried using ViewGroup.bringChildToFront() and using the view returned by the fragment's getView() but this hasn't worked. I've also found out that you can nest fragments on Android 4.2+ with getChildFragmentManager(), but I'm supporting older APIs, and this method doesn't seem to be in the support library.
Any help greatly appreciated!
The way I got around this was to manually recreate the third fragment after the orientation change, and remove the one created by the system.
My layout sometimes does not position elements properly. I tried a lot of solutions but unique working one is rotate from portrait to landscape and then return from landscape to portrait. Then layout is automaticaly redrawed and fits perfectly. I set orientation|keyboard so content is not reloaded, only redrawed. How to redraw content programmaticaly like landscape-portrait does? Thank you.
EDIT: I tried following and has no effect
getWindow().getDecorView().findViewById(android.R.id.content).invalidate();
getWindow().getDecorView().findViewById(android.R.id.content).requestLayout();
Activity has set main layout on onCreate setContentView(R.layout.main);
Layout "main" contains a TabHost and Admob.
Layout "view" contains a webview ("id:myWebview") that is shown on tab1.
And also tried to invalidate them! webview, layout main and layout view and crashes
Did you try to invalidate() the root view?
findViewById(android.R.id.content).invalidate();
This should redraw the whole layout.
When screen orientation changes, Android recreates the current Activity.
Try calling measure(int, int) or requestLayout(). Otherwise there is no chance to programmatically relayout views.
Call requestLayout() only and read View class description for more informations.
If this is unsafe or bad practice please do correct me. I tried all these methods as well and out of desperation decided to just try calling my onCreate again and it worked. So for now I'll be using onCreate(null) to refresh my view when I update data. Again, please let me know if this is unsafe or a bad practice and if possible a working alternative.
I am writing an app that uses Fragments for the UI, very similar to the Notepad sample code. It has a List of items then an editor for these items. In landscape mode the list and editor fragments are positioned side by side, but in portrait mode only the list is shown in the main activity, and the editor is shown by launching a new activity.
Within my editor fragment I have calls to findViewById to get at the individual components of the UI (mostly EditText fields). Under normal conditions this all works fine, but when the screen is rotated from landscape to portrait and the main activity is destroyed and created again it seems to call onActivityCreated (plus other callbacks) on my editor fragment even though it is not part of the display now (since in portrait mode it is just the list that is shown).
The problem is, findViewById to get the UI components returns null (I'm guessing because the fragment is not being displayed). But why are the calls being made at all? It is making me need null checks everywhere to make sure I don't try and use the UI components when they aren't on screen.
when the screen is rotated from landscape to portrait and the main activity is destroyed and created again it seems to call onActivityCreated (plus other callbacks) on my editor fragment even though it is not part of the display now (since in portrait mode it is just the list that is shown).
Correct. Android recreates all existing fragments during a configuration change. Or, if the fragment was added using a FragmentTransaction and you used setRetainInstance(true), the exact same fragment object is retained during a configuration change.
But why are the calls being made at all?
See above.
The problem is, findViewById to get the UI components returns null
You only need to call findViewById() in onCreateView(), and there you know whether the "UI components" exist, because you are creating them yourself.
It is making me need null checks everywhere to make sure I don't try and use the UI components when they aren't on screen.
Then use isVisible() or one of the other is...() methods on Fragment. Or, use setRetainInstance(true) so your fragment is not destroyed and recreated. Or, remove the Fragment (e.g., in onCreate() of the activity, if the passed-in Bundle is not null and you are now in portrait).