So, Fragments

honeycomb fragments

Search for: honeycomb fragments

FragmentManager

Search for: FragmentManager

Fragments

Search Google for: Fragments

Search Android Developers Group for: Fragments

Search Android Beginers Group for: Fragments

Search Google Code for: Fragments

Search Android Issues Database for: Fragments

How to blog from google on fragments

As quoted from the article above

As you rotate the device an activity gets destroyed and recreated. In the process you are forced to remember the state and recreate it. Fragments can be automatically saved and restored.


Fragment
ListFragment
FragmentManager
FragmentTransaction
<fragment> tag
onActivityCreated
onCreateView

FragmentTransaction

Search for: FragmentTransaction

A (brief) nice article that explains a bit of FragmentTransaction

Allows you to attach a fragment (which provides a view) to a layout id (place holder for a fragement's view). Or replace.

Provide the way you want to animate that show of the fragment

Allow the "back" affordance :) (hope as heaven I am right)

show/hide a fragment or remove a fragment

Allow breadcrumbs for back

Android developer news blog: androidphoneguides.com

There is not a huge list. A handful of articles on 3.0. Perhaps more to come. wait and see.

A nice analysis of android sample app in honeycomb

This blog talks about fragments, action bar etc.

A derived fragment needs to have a default constructor with no arguments. Given that the pattern to do this


SomeDerivedFragment sdf = new SomeDerivedFragment();
Bundle args = new Bundle();
args.put("somekey", "somevalue");
args.put("someohterkey","someothervalue");
sdf.setArguments(args);

onCreateView(...)
{
    Bundle argBundle = this.getArguments();
    somestuff = 
       argBundle.get("somekey","some_default_value");
}

Perhaps may be this will allow the fragment's state to be saved through the bundle....

An arbitrary name you choose for a fragment. You can use this name later to locate the fragment using the fragment manager. The method to use is

findFragmentByTag(string)

it is interesting. views are located through their resource ids. however the fragments by their tag names.

This is done through a container. This container appears specifically to be a view. one can pass the resource id of this view. Looks like you can pass a null or 0 for this indicating it is not to be placed in any container.

Not sure then what you do with it??


public class DetailFragment 
extends Fragment
{
    public View onCreateView(LayoutInflater inflater,            
            ViewGroup container, 
            Bundle savedInstanceState)
    {
        View v = inflater.inflate(R.layout.main,null);
        TextView tv = (TextView)(v.findViewById(R.id.textViewId));
        setPrompt(tv);
        return v;
    }
    public static DetailFragment newInstance(String sometext)
    {
        DetailFragment df = new DetailFragment();
        Bundle args = new Bundle();
        args.putString("prompttext", sometext);
        df.setArguments(args);
        return df;
    }
    private void setPrompt(TextView tv)
    {
        String s = getPrompt();
        if (s == null)
        {
            s = "No prompt text avilable";
        }
        tv.setText(s);
    }
    public String getPrompt()
    {
        Bundle b = this.getArguments();
        if (b == null) return null;
        String ps = b.getString("prompttext");
        return ps;
    }
}//eof-class

In an activity a fragment transaction allows you to "batch up" a number of operations on a number of fragments. This batch of operations can be replayed if you add that transaction to the "back" stack.

SO what is a back stack?

Usually the back button moves you from an activity to activity. This facility is extended to fragment. More precisely "fragment transactions". when you add these "series of fragment actions" as a "back" to the activity, the activity's back will not go to the previous activity but instead play back this entire "series of fragment actions". This will occur until no back fragment transactions are available. And then the previous activity is shown.

To make use of this facility all you have to do is


FragmentTrasaction ft;
ft.replace(fragment1);
ft.replace(fragment2);
ft.replace(fragment3);
ft.addToBackStack("tx_name_1");
ft.commit

Then you can repeat this code again


//change something about
//fragment1, 2, and 3. and do
FragmentTrasaction ft;
ft.replace(fragment1);
ft.replace(fragment2);
ft.replace(fragment3);
ft.addToBackStack("tx_name_2");
ft.commit

Now if you hit back, you will tx_name_1 replayed.

This is why it is called a transaction because we are repeating a series of actions with a start and stop point

Who is Dave?


//Psudeo code only.

//Default constructor for 
//Auto instantiation
MyFragment(){}

//Specific client explicit Constructors
public MyFragment(arg1)
{
   this(arg1,arg2);
}

public MyFragment(arg1, arg2)
{
  Bundle bundle = new Bundle();
  bundle.put("arg1key",arg1);
  bundle.put("arg2key",arg2);
  setArguments(bundle);
}


<fragment class="com.androidbook.fragments.MyListFragment"            
   android:id="@+id/titles" 
   android:layout_width="match_parent"
   android:background="@android:color/white"
   android:layout_weight="50"            
   android:layout_height="wrap_content" />

public class MyListFragment extends ListFragment
{
    private static String tag = "MyListFragment";
    private Context m_ctx = null;
    private IReportBack m_reportBack = null;
    public MyListFragment()
    {
    }
    @Override    
    public void onActivityCreated(Bundle savedState) 
    {        
        super.onActivityCreated(savedState);
        DebugActivity activity = (DebugActivity)getActivity();
        m_ctx = activity;
        m_reportBack = activity;
        
        // Populate list with our static array of titles.        
        setListAdapter(new ArrayAdapter<String>(getActivity(),                
                android.R.layout.simple_selectable_list_item,                
                new String[]{"one","two","three"}));   
      }
    @Override    
    public void onListItemClick(ListView l, View v, int pos, long id) 
    {
        m_reportBack.reportBack(tag, "Position:" + pos);
        FragmentTransaction ft = this.getFragmentManager().beginTransaction();
        Fragment detailFragment = DetailFragment.newInstance("Position:" + pos);
        ft.replace(R.id.details,detailFragment);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        ft.addToBackStack(null);
        ft.commit();
    }
    
}//eof -class

Finds a fragment that was identified by the given tag either when inflated from XML or as supplied when added in a transaction. This first searches through fragments that are currently added to the manager's activity; if no such fragment is found, then all fragments currently on the back stack are searched.

Finds a fragment that was identified by the given id either when inflated from XML or as the container ID when added in a transaction. This first searches through fragments that are currently added to the manager's activity; if no such fragment is found, then all fragments currently on the back stack associated with this ID are searched.


A
  F1 (3,2,1)
  F2 (1)
  F3 (5,4,3,2,1)

Explanation:

Activity A has three fragments
F1, F2, F3

F1 has a stack depth of 3
F2 has a stack depth of 1
F3 has a stack depth of 5

A discussion: Fragment question: inter-frag​ment communicat​ion?

A discussion: Can a fragment hold local variables

One isn't needed as one can use their regular pointers ...

Discussion: Direct pointers to fragments

Yes one can maintain direct pointers. See the posts for a bit more detail


onSaveInstanceState()
{
 fm.putFragment(myfragment,bundle,"myfragment");
}

onRestoreInstanceState()
{
 this.myfragment = fm.getFragment(bundle,"myfragment");
}

An activity owns all its fragments

An activity has a variable list of fragments

An activity will save and restore and these fragments as the activity is saved and restored

You can hold pointers to these fragments with in a single life time of an activity

Make sure to restore fragment pointers (if you hold them directly) during rebirth

Fragments are essentially unfastened objects that are placed in a collection for better state management

ofcourse there is the added stack operations on top of this essential facility

Each fragmetn is responsible for saving and restoring its internal state through save/restore methods just like an activity

if the fragment is added to the fragment manager, the fragment manager will save and restore that fragment. So it makes sense to request that pointer to that fragment.

Given that nature of fragment restoration, getFragment and putFragment make sense only if the fragment is added.

So the convenience of get and put fragments, and hence direct pointers to fragments may not always work out if you don't have control of when fragments are automatically removed. An example is dismissing dialog.

When you add a fragment as a part of your activity layout, it lives in a ViewGroup inside the activity's view hierarchy and the fragment defines its own view layout. You can insert a fragment into your activity layout by declaring the fragment in the activity's layout file, as a element, or from your application code by adding it to an existing ViewGroup. However, a fragment is not required to be a part of the activity layout; you may also use a fragment without its own UI as an invisible worker for the activity.

Handling the fragment lifecycle

To provide a layout for a fragment, you must implement the onCreateView() callback method, which the Android system calls when it's time for the fragment to draw its layout. Your implementation of this method must return a View that is the root of your fragment's layout.

The system inserts the View returned by the fragment directly in place of the <fragment> element.

Each fragment requires a unique identifier that the system can use to restore the fragment if the activity is restarted (and which you can use to capture the fragment to perform transactions, such as remove it). There are three ways to provide an ID for a fragment:

Supply the android:id attribute with a unique ID.

Supply the android:tag attribute with a unique string.

If you provide neither of the previous two, the system uses the ID of the container view.

When you are adding a fragment, you are always adding it to a view group, not to a view

in other words you want to track all your adds as a single unit....

In this case you don't need a viewgroup to add it to! This is then strictly to manage or hold on to pointers when the activity restarts!

It is same as simulating a back button for fragments

If I don't call this then I am merging the current fragments into the current state of the UI. No demarcation. Much like me changing any other view!

if I call add to back stack then, I am saying, This unit of work, is a separate layer from the original UI, and when I want to go back take me to the original state!!

So, if I start with an activity with no fragments at all, the original state is the state of the activity with its UI

Now I add 2 fragments. I don't put them on the back stack. Now If I go back the whole activity will go back to its previous activity as if the fragements are just views. (This is what I am thinking and probably right)

On the other hand

if I were to add the same 2 fragments to the back stack and I go back. Now the original activity stays and redisplayed (I think...)

if adding fragments is time sensitive, you may want to call this method otherwise the commit will happen on the UI thread loop.

Fragments have methods that can contribute menu options to the activity

Android advises that two fragments should never communicate directly!!

The link above states the following

Often you will want one Fragment to communicate with another, for example to change the content based on a user event. All Fragment-to-Fragment communication is done through the associated Activity. Two Fragments should never communicate directly.

understanding android fragments

Search for: understanding android fragments

Unbelievable how much is written about these fragments by looking at these search results! a boat load

It is worth reading some stuff on setRetainInstance

setRetainInstance()

Search for: setRetainInstance()

Here is its discussion on sof

Here is the api doc on this method

Control whether a fragment instance is retained across Activity re-creation (such as from a configuration change). This can only be used with fragments not in the back stack. If set, the fragment lifecycle will be slightly different when an activity is recreated:

onDestroy() will not be called (but onDetach() still will be, because the fragment is being detached from its current activity).

onCreate(Bundle) will not be called since the fragment is not being re-created.

onAttach(Activity) and onActivityCreated(Bundle) will still be called.

whats up with setTargetFragment? here is the API

it says...

Optional target for this fragment. This may be used, for example, if this fragment is being started by another, and when done wants to give a result back to the first. The target set here is retained across instances via FragmentManager.putFragment().

fragment: The fragment that is the target of this one.

requestCode: Optional request code, for convenience if you are going to call back with onActivityResult(int, int, Intent).

setTargetFragment

Search for: setTargetFragment

This might throw some light on this subject

In something like dialog fragments fired off from non dialog fragments can establish a parent child relationships which are maintained across configuration changes.

Although they could be employed for any two random fragments in that activity, this appears to define a more tight relationship when needed.

The general recommendation may still hold where inter fragment communication is encouraged through the parent activity which may be aware of the fragment context better.

if your fragment wants to remember pointers to 4 other fragments in that activity and assume that they will all be there when it is rotated you can use put fragment and get fragment in the bundle to reestablish connectivity!

The setTargetFragment appears to be a shortcut when you are focusing on one parent fragment.

If you are wondering what the requestCode is, see this article on startActivityForResult

Because the caller has only one callback method for any number of activities that may be started, he/she needs to know which activity is it that was started!

Or you have the option in case of target fragments to explicitly name a method and not worry about the request code at all!!

The following methods are called in that order.


1. onAttach
2. onCreate
3. onCreateView
4. onActivityCreated
5. onStart
6. onResume

SO which one is appropriate to put the initialization code?

An activity gets attached in onAttach. Activity has no views at that time. As you move down the onCreate also is not ready to see the finsihed views in an activity. The onCreateView is there to supply the view of this fragment. Also onCreateView may not be called under some valid circumstances.

So only in the onActivityCreated all views are ready to go.

So it depends on why you need the initialization for. If you can wait, then onActivityCreated is your guy/gal. onCreateView is a bad choice as it may not get called.

You may even want to wait until onStart or onResume under some circumstances.

I have used onStart when I did the ADOs (Activity Dependent Objects). This probably was ok if these objects are purely delegated objects and activity doesnt draw from them for its UI state.

The picture is not true probably if the activity relies on these retained objects for its UI state to be constructed.

So perhaps I should move them to the begining of onCreate right after calling the super.

This will ensure the onCreate can rely on the existence of retained fragments,.

This might prompt me to put a callback on a base class to say


onInitRetainedObjects()
{
   //register your root retained objects
   //register your retained fragments
}