Page 3 of 5
Let's suppose that the layout we have just created is only suitable for a large or xlarge display. We need to create a layout based on the default layout for a large display. To do this all you do is load the main layout into the designer select the display icon at the top left of the designer and then select Create Other.
From the dialog box that appears select size and from the drop down list select large:
When you click OK a new layout folder layout-large is created containing a copy of the default layout.
If you run the app again you will see no difference because the default and large layouts are the same. To see a difference we need to remove Fragment2 and its container from the default layout leaving just the single container and Fragment1.
Now if you run the app using a Nexus 7 emulator you will see both Fragments but if you run it using a Nexus 4 emulator you will see just one Fragment.
Alternatively you can view the layout in different devices within Android Studio. Either way you will see more or less the same thing - one Fragment on normal sized screens and two Fragments on large screens.
The Fragment Manager
Our next task is to arrange for the normal screen to dynamically swap which Fragment is on display and to do this we are going to have to make use of the FragmentManager.
We have used the FragmentManager in earlier chapters to dynamically add Fragments to an Activity but now we need to look at how it all works a little deeper.
Each Activity has a FragmentManage that keeps track of the Fragments that that are in use.
The FragmentManager works in terms of Transactions which are sets of instructions that are only acted on when the commit method is called.
The typical idiom is to get the FragmentManager and then call its beginTransaction to return a FragmentTransaction object which provides methods for each action that you can perform.
As each action returns the same FragmentTransaction object method calls can be chained:
The most commonly used action is to add a Fragment but this is slightly more subtle than you might expect because it adds the Fragment to the FragmentManager not to the Activity. If you can avoid thinking of the add method as adding the Fragment to that Activity but to the FragmentManager you will find things much easier to understand.
There are three version of the Add method:
each one adds the fragment to the FragmentManager but the first two also add the fragment's View to the Activity as a child of the specified container.
You can also specify a string tag that can be used to retrieve the fragment from the FragmentManager.
Notice that adding a Fragment to the FragmentManager isn't just a matter of displaying its View in the Activity indeed you can add a Fragment without displaying its View.
The point is that the FragmentManager "looks after" the Fragments in the sense that while the Activity is alive so are the Fragment objects.
As long as a Fragment is in the FragmentManager its state is preserved.
You can remove a Fragment from the FragmentManager in two ways:
The first simply removes the specified fragment from the FragmentManager the second removes all of the Fragments that are displayed in the specified container and replaces them with the supplied fragment. The Fragment is identified for the future using the string tag. There is a version of the replace that you can use without specifying a tag.
Any Fragment that is removed from the FragmentManager has its UI removed from its associated container, if any. Notice that you need to think of these operations are removing the Fragment from the FragmentManager and not from the container - removing the UI is almost a side effect.
When you remove a Fragment from the FragmentManager it is destroyed and it is up to you to ensure that it is created and any data restored if it is needed again.
The only exception to this rule is if the transaction is placed on the BackStack when the Fragment is stopped but not destroyed - more of the BackStack later.
Clearly if you can it is a good idea to keep Fragments that you want to keep using in the FragmentManager.
However to do this you need to be able to control which Fragments are on display in their containers and which aren't.
The key to controlling which Fragments are displayed in their containers is the detach and attach methods. Following:
the fragment specified is still in the FragmentManager but its View hierarchy is destroyed and hence no longer shows in the container it was associated with.
To restore the View hierarchy and display it within its container you use:
You can also use hide and show but these simply hide and show the View hierarchy in the container and do not remove it from the layout. Hide and show are sometimes useful but in most cases it is detach and attach you need to use to dynamically switch which Fragments are on display.
The important point is that detach and attach control which Fragments are on display and hence part of the current UI but they do not remove the Fragment from the FragmentManager so it their state is preserved.
The FragmentManager also has some useful methods that help with working with the Fragments it is looking after.
In particular you can use the
method to return a Fragment you added to the FragmentManager with the same tag. There is also a findFragmentById command but this only works with Fragments that have been added using an XML layout file because it is difficult to assign a dynamic Fragment an id.
One complication of using findFragmentByTag is that it searches the Fragments currently added to the FragmentManager and it searches the BackStack for any that might have been removed but added to the BackStack. What this means is that findFragment can return a Fragment that isn't currently added to the FragmentManager and this can sometimes be a complication.
The Fragment also has some useful methods that tend to be used along with the FragmentManager:
returns true if the Fragment is added to the FragmentManager.
returns true if the Fragment is detached.
returns true if the Fragment is hidden
You can think of and use the FragmentManager as the repository of all of the Fragments your Activity is using and use it to control what Fragments are part of the UI.
Let's see how to do this for the two Fragment examples we have been developing so far.