Understanding Fragments through Key Questions

satya - 9/26/2013 9:59:31 AM

What is a Fragment?

An activity in android is a standalone window that has a life cycle of its own. It is a unit. It is a component. It displays a collection of views and other view containers called view groups.

An activity may and likely will get restarted when a device rotates. So any object that is holding a reference to this activity will have a hanging pointer as the newly created activity will have a new pointer.

A fragment servers multiple purposes in helping an activity.

It is not a view nor is it an activity. it simply inherits from a base java object.

Much like an activity a fragment is a container of other views. These views are loaded from a layout like any other collection of views in android.

A fragment gives you the ability to package views and behavior into a reusable asset. This is much like a portlet or a widget on a web page.

A fragment has the option of telling its activity that it needs to be retained when the activity is restarted. This is very useful as these retained fragments can hold pointers across activity restarts.

As a fragment is not a view by itself, it can be used purely for its life cycle and pointer retention purposes. Some times it is called a headless fragment.

In essence it aids with


Reusable UI - A basic fragment behavior
Pointer retention - Headless fragment
Back button help - fragment transaction

Much like activities have a back stack, a fragment, (being a portlet), can have its own states (or the states of a collection of fragments) remembered and managed by the back button. This is done through what are called fragment transactions.

satya - 9/26/2013 10:05:59 AM

How do you create a fragment?

You extend a fragment first into a derived fragment.

you need to override one of its methods to load a view layout.

You new a fragment and attach it a bundle of arguments that can be used later at the appropriate callback time to initialize its internals. the bundle represents the initial state of the fragment.

There are the usual activity like lifecycle methods to get to the state instance bundle when needed. The initial argument bundle is different from the instance state bundle.

The derived fragment is a java class of your own.

The derived fragment can be added to a view group programmatically

A fragment can have a name and also an id to locate it again. You use a fragment manager that is with the activity to locate your fragment.

You can also add a fragment in a layout file. However the layout file does not specify the sub layout for this fragment. the layout for a fragment, so far in the current releases, is loaded always programmatically.

A fragment can be restarted just like an activity. So any construction needs to be done appropriately through appropriate callbacks.

refer to the apis docs to see the patterns of initialization. there is really no mystery to this.

satya - 9/26/2013 10:14:52 AM

How do you add a fragment?

A fragment is always added to a view group as a child of that view group. If no id is specified when you are adding it to the view group it acquires or uses the id of the viewgroup.

A fragment is never added directly to a view group. Instead it is added through fragment transaction. A fragment transaction is a "batch" of fragments that are added or removed. This allows for the back button to recreate the back experience.

Of course a fragment is added through a layout file for the activity as well. My suspicion then is that all the initial fragments are added by the framework behind scenes in a transaction and committed with the activity as if they are part of the same state.

satya - 9/26/2013 10:24:38 AM

Tell me more about a Fragment Transaction?

A fragment is never added directly to a view group. Instead it is added through fragment transaction. A fragment transaction is a "batch" of fragments that are added or removed. This allows for the back button to recreate the back experience.

Once you perform a series of adds, deletes, or any other operations that a transaction may allow, you commit them so that you can apply them to the activity. Before committing you can request the series of actions to be applied to a back stack.

If you don't request adding to the back stack, then it is as if the current state of all the fragments that are in the activity is merged with the current activity state.

In other words adding to the back stack, creates a new layer of UI, that can be peeled back on the back button.

As the UI or fragments get peeled back they get callbacks similar to an activity being paused, stopped, etc.

satya - 9/26/2013 10:32:55 AM

How do you load a view into a fragment?

Usually you load views through layouts.

Because a fragment can be indicated through its classname, just like a custom view component, in the layout file, it is reasonable to question if we could add its layout embedded in the layout file!

No you can't. it follows the activity much closer than a custom component in that perspective. You have to load a fragments view programmatically!

You do this in onCreateView callback.

satya - 9/26/2013 10:35:37 AM

Show me an example of loading a view for a Fragment


public class DetailFragment 
extends Fragment
{
    ....other methods

    public View onCreateView(LayoutInflater inflater,            
            ViewGroup container, 
            Bundle savedInstanceState)
    {
        View v = inflater.inflate(R.layout.main,null);
        //do something with the view
        //such as set it up using your
        //current and initial state
        return v;
    }
....other methods
}//eof-fragment class

satya - 9/26/2013 10:59:53 AM

So what does a Fragment's life cycle look like?

satya - 9/26/2013 11:13:29 AM

Map these states to activity states for me

satya - 9/26/2013 11:14:40 AM

Key callback: onAttach() and onDetach()...

The activity is created and associated with this fragment. The activity pointer is passed in.

satya - 9/26/2013 11:15:11 AM

Key callback onCreateView()

load your layout and return it here.

if you add a fragment without specifying a view group to attach it to, you get a head-less fragment. For such fragments onCreateView() won't be called and hence need not be implemented!

One of the arguments to this method is the parent view group to which the returned view would be added. However you are advised not to add it yourself to the view group. Framework does this for you when you return the view.

You can use the passed in view group however to read layoutparams as per the documentation or in other words discovering something about that viewgroup (through its read apis)

At times during rotation changes your target layout may not contain the view group that was originally used to create and attach the fragment. In such a case you have to check for null and if it is don't create the view and instead return a null.

satya - 9/26/2013 11:16:47 AM

Key callback: onActivityCreated()

The onCreate() method of the activity has returned. This means all the views have been set including the views of other fragments!

satya - 9/26/2013 11:24:04 AM

Are there any good guides on Fragments?

See the links on the top right

satya - 9/26/2013 11:48:04 AM

Tell me about fragment arguments?

A fragment, may not be willy nilly, but almost willy nilly, can get recreated by the container, in this case the activity or the android framework.

in this sense a fragment is MANAGED!

MANAGED is a term used in computer science where a piece of code is registered as a component and that component then can be moved around, recreated, redeployed etc.

A servlet in java is an example.

A portlet is another example.

When a servlet is reusable, it may need to be configured with parameters that specializes its behavior. these are typically mentioned in a config file.

Except in a fragment, when you instantiate and hand over the fragment to an activity, you have a similar option of seeding it with some behavioral parameters.

In this analogy these initialization (or parametrization) arguments are set during construction using a method called "setArguments(bundle)".

The same arguments can be later recalled using getArguments and used for decision making.

Due to theri parametrization nature, there are some restrictions on calling this method after a fragment is fully created.

There appears to be two patterns of using these arguments.

In pattern 1, a static method is provided on the derived fragment class with the input arguments.

In pattern 2, in addition to the required default constructor, a constructor with argument is provided instead of a static method.

Android in all its examples seem to prefer pattern 1. However I haven't seen a reason why the pattern 2 won't work!

satya - 9/26/2013 3:50:01 PM

How do fragments help with configuration changes?

Say you start with an activity. You add a few fragments to it. You have some code in those fragments that is manipulating the activity in someway. The device rotates.

In the onCreate() method of the activity the developer is responsible for recreating the views. However you don't need to recreate the fragment, unless of course you want to due to more space available!. The activity is reattached to the recreated fragment. Of course, the fragment will need to recreate its views due to its own start.

So in a way Android restores the actvity skeleton including its relationship to other fragments. The flesh will need to be flushed out by the developer code.

You could also tell the fragment that it does'nt need to be created! In this case the activity is recreated but not the fragment. One can use this property to create fragments just to retain the state!!

This later property can be used to kick of asynctasks and report their status back on the main activity or a fragment dialog as the connectivity to the activity or the fragment dialog is automatically reestablished after the activity restart.

However your code must be smart enough that there is a time in which the activity may be null until the right callback is established.

satya - 9/26/2013 4:08:40 PM

Does onCreateView() get called for a head-less fragment?

if you add a fragment without specifying a view group to attach it to, you get a head-less fragment. For such fragments onCreateView() won't be called and hence need not be implemented!

satya - 9/26/2013 4:26:44 PM

Will fragments be recreated on configuration change automatically even if they are not in the layout?

Read this quote from the fragment api!

When a configuration change causes the activity hosting these fragments to restart, its new instance may use a different layout that doesn't include the same fragments as the previous layout. In this case all of the previous fragments will still be instantiated and running in the new instance. However, any that are no longer associated with a tag in the view hierarchy will not have their content view created and will return false from isInLayout(). (The code here also shows how you can determine if a fragment placed in a container is no longer running in a layout with that container and avoid creating its view hierarchy in that case.)

satya - 9/26/2013 4:53:11 PM

Implications of adding a Fragment using a container id and not a view group pointer?

if you notice adding a fragment to its view group, the fragment transaction API does not take a pointer to the ViewGroup!! It takes its container id. Why is this important?

Because this id, and not the pointer, allows the activity to reattach the recreated fragment to the right view group using its id. If it were to use a pointer, the pointers would have been different on recreation.

if the target layout doesn't contain that view group or container then onCreateView may be called with a null parent! (I wonder if it is even called...)

satya - 9/27/2013 9:35:32 AM

How do I communicate between two fragments?

In my feeble mind this ought to be the stupidest question. It is much like in 1972 I was asked to debate as a middle school student "Does women need education?" The right answer always has been "Why do you even ask?"

Yes a fragment can talk to another fragment as much as it wants if only it can find it. we know it can find another fragment. Then what is the problem?

Fragments get recreated. So the pointers across rebirth are not good. As long as you can reacquire those pointers you are gold!!

How do you reacquire those pointers? Well you locate them by their name or id. Or you can use the "Book the trunk call approach!" where you ask the Activity to relay the messages.

Or you can save and restore fragments through the bundle. The bundle does the dirty work of storing the tag names in the bundle and restoring them to pointers.

This later approach is further shortened where you can pick a "close friend" (as long as it is only one) and call it a target fragment. When you set the target fragment on your fragment, the framework will save references to that fragment before and after rebirth!!

There you have it!!

satya - 9/27/2013 9:52:21 AM

What would you say then the key topics in Android fragments are?


How to create fragments and attach them to activities?
Fragment transactions
Behavior of fragments due to device rotation
Headless fragments
Retaining fragment instances across configuration changes
Communication between fragments 
Using a target fragment
Fragment dialogs
Wise use of fragments as fragments 
Elastic fragments: Being able to respond to varying conditions