Interpreting Android's Fragment

Source: Internet
Author: User

This document is translated from Android official documentation, combined with your own tests, organized as follows.

Overview

Fragment represents a behavior or part of the UI in activity. We can use multiple fragments in one activity or reuse a fragment in multiple activities. We can use fragment as part of the activity modularity, fragment has its own life cycle, UI layout. We can dynamically add or remove fragment while the activity is running.

Fragment must be embedded in the activity, and the life cycle of the fragment is affected by the host activity. For example, when activity is paused, all fragments in the activity also go into a paused state, and when activity is destroyed, all fragments in the activity are destroyed. However, when activity is running, we can handle each fragment individually, for example we can add or remove them. When we finish a fragment transaction, we can also add fragment to the back stack, which is managed by the host activity, and the entities in the stack record the transaction operations that occurred fragment. With the back stack, we can return to the state before the fragment transaction occurs by pressing the home key.

When we add fragment to the activity layout, it is saved in ViewGroup and the ViewGroup is added to the Activity view hierarchy, fragment can define its own layout file. You can add fragment through a label in a layout file <fragment> , or add it to an existing ViewGroup by code. But fragment does not have to be part of the activity layout; we can still use fragment without layouts to handle tasks that are not displayed by the activity.

Detailed usage of fragment is described below.

Design philosophy

Android has introduced fragments from 3.0 (API11), primarily to support more dynamic and flexible UI designs, such as tablets, on large screens. Because the tablet screen is much larger than a handheld device (mobile phone, etc.), there is more room to store and interact with the UI components. Fragments can automate the design of view hierarchy changes without our management. By dividing the activity layout into fragments, we can change the rendering state of the activity while the activity is running, and we can manage those changes in the back stack, which is managed by the host activity.

For example, a news application can use one fragment on the left to display a list of headings, and another fragment on the right to display specific news content. These two fragments are in the same activity, one left and one right, and each fragment has its own life cycle approach and handles its own input events. In this way, we can avoid using two activities to achieve this effect. As shown in the following:

We should design the fragment as a modular reusable activity component. This is because each fragment can define its own layout, has its own life cycle, we can use the same fragment in multiple activities, so we should design reusable to avoid having to manipulate the other fragment directly in fragment. The modular fragment allows us to vary the combination of fragments depending on the screen size. When the design program supports both tablet and mobile, we can reuse our fragments in different layout configurations, so as to adapt to different screen space and improve the quality of the user's physical examination. Example of the news client above. For large-screen tablets, you can display news headlines and news content in one activity at the same time two fragment, and for mobile phones, a fragment can only be placed in one activity.

Create fragment

In order to create a fragment, we must create a subclass of the fragment class (or its subclasses). Life cycle methods in fragment and activity have many of the same places. For example fragment also contains:,, onCreate() onStart() , and onPause() onStop() so on. In fact, if we want to use fragment for an existing application, we just need to move the code in the activity's callback method to the corresponding fragment callback method.

In general, we must implement at least one of the following methods:

-onCreate()
This method is called by the system when the fragment is created. We should initialize the necessary components here, which are still retained when the fragment enters a pause or stop after a reboot.
- onCreateView()
The system calls this method when the UI layout is first prepared for frgment. In order to paint the UI layout for fragment, the method must return a view object as the root of the fragment layout. If fragment does not provide a layout, the method returns NULL.
- onPause()
The system calls the method when the user is about to leave the fragment (leaving but not necessarily destroying the fragment). Usually we need to keep the information that needs to be persisted here because the user may not be back.

Other methods of life cycle are described in detail in the subsequent processing fragment life cycle.

In addition to the base class fragment, we also have a few subclasses that inherit fragment:

    • Dialogframent
      Appears as a dialog box.
    • Listfragment
      Appears as a list of items.
    • Preferencefragment
      Displays the hierarchy of preference objects as a list, similar to preferenceactivity. This is useful when creating an activity in a program that is set up like this.
Add UI

Fragment is often used as part of the activity UI, and fragment contributes its own layout to the activity.

To provide the layout of the fragment, we must implement the method that is onCreateView() called by the system when the system starts to create the fragment layout. At the same time, the method must return a view as the root of our frament layout.

Note: If our fragment is a subclass of Listfragment, the method returns a ListView by default, so we do not need to implement the method.

In order to onCreateView() return a layout, we take advantage of the layout file defined in XML, in order to achieve this, the onCreateView() Layoutinflater object parameter is provided. For example:

publicstaticclass ExampleFragment extends Fragment {    @Override    publiconCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        // Inflate the layout for this fragment        returnfalse);    }}

Where the parameter ViewGroup object represents the parent view (from the activity layout), our fragment layout needs to be inserted into the layout. The bundle object is used to save the previously running fragment state, and returns null if it did not previously exist.

The Layoutinflater object inflate() method passes three parameters:

    1. The ID of the loaded layout file.
    2. The parent view of the loaded layout, that is, the parent view as the root layout of the fragment layout.
    3. A Boolean indicates whether the layout loaded during the load depends on the parent layout (the second parameter). False is passed here because the system has inserted the loaded layout into the ViewGroup object, and if true, a redundant view is created in the final layout.

Through the above introduction we know how to create a fragment with layout, below, we describe how to add fragment to the activity.

Add fragment to Activity

In general, fragment as part of the host activity layout, there are two ways to add fragment to the activity:

  1. Static loading
    This method declares the fragment control by declaring it in the activity layout file. In this case, we can specify the layout properties of the fragment as specified in the view. For example, an activity layout with two fragments is declared below:

    <?xml version= "1.0" encoding= "Utf-8"?><linearlayout  xmlns: Android  = "http://schemas.android.com/apk/res/android"  android:orientation  = "horizontal"  android:layout_width  = "match_parent"  android:layout_height  = "match_parent"  > <fragment  android:name  = "com.example.news.ArticleListFragment"   Android:id  = "@+id/list"  android:layout_ Weight  = "1"  android:layout_width  =< Span class= "Hljs-value" > "0DP"  android:layout_height  =" match_parent "/> <fragment android:name="Com.example.news.ArticleReaderFragment"android:id ="@+id/viewer"android:layout_weight= "2"android:layout_width="0DP"  android:layout_height="match_parent" />                                </linearlayout>

    In the <fragment> label, the android:name attribute specifies the fragment class that needs to be instantiated.

    When the system creates an activity layout, it instantiates each fragment specified in the activity layout, retrieves the onCreateView() appropriate layout, and inserts the layout into <fragement> the corresponding label's location.

    Note: Each fragment needs to provide a unique identifier through which the system can save these fragment (when the activity is restarted). The following three ways are specified:
    1. In <fragment> tag by android:id to specify an ID;
    2. At <fragment> The tag specifies a string by Android:tag ;
    3. If neither of the above is specified, the system uses the ID of the parent control (the second parameter of the inflate () method).

  2. Dynamic loading
    This method refers to dynamically adding fragment to an existing viewgroup. At any time when the activity is running, we can add fragment to the activity. We only need to specify a ViewGroup object to be replaced by fragment.
    If you want to perform a fragment transaction operation in activity (a transaction is an atomic operation, a transaction is either executed or not.) Fragment transaction operations such as: Add, delete, replace fragment), we can use the Fragmenttransaction class, you can do the following:

    FragmentManager fragmentManager = getFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

    We can use the add() method to add fragment, which add() receives two parameters: the parent layout to be inserted and the fragment object to add. As follows:

    new ExampleFragment();fragmentTransaction.add(R.id.fragment_container, fragment);fragmentTransaction.commit();

    The commit transaction execution needs to be invoked every time the transaction is executed using the Fragmenttransaction object commit() .

Add fragment with no UI layout

The above describes how to provide UI layout to activity through fragment. However, we can also use fragment without layout, which fragment can provide back-office services.

To add fragment with no UI layout, we can add fragment in activity using the add(Fragment,String) string object as the fragment Tag property. Since the fragment does not require a UI layout (not associated with the activity layout), we do not have to implement it onCreateView() .

Using the tag string is not a strictly non-layout fragment, and we can also provide a tag string for fragment with layout. However, if fragment does not have a relevant layout, then the tag string is the only way to identify the fragment. If you want to use the fragment later, you can pass findFragmentByTag() .

For background fragment, you can refer to the previous content: Keep an object for recovery data when the configuration changes.

Management fragments

In order to manage fragments in activity, we can use the Fragmentmanager object, which can be obtained through ' getfragmentmanager () in the activity.

We can complete the following matters through Fragmentmanager:

    • Fragments that findFragmentById() exist in the activity can be obtained either by (getting a fragments with UI layout) or by findFragmentByTag() (getting a fragments with/without UI layout).
    • By popBackStack() ejecting the fragment from the back stack (impersonate the user back command).
    • By addOnBackStackChangedListener() registering an event listener for the back stack.

For more information on the Fragmentmanager class, refer to the official documentation.

The previous section describes a transaction operation that can be opened through fragmenttransaction, which is described in detail below.

Performing fragment Transactions

With fragment transactions, we are able to complete Add/delete/replace operations. The collection of each operation can be called a transaction. We can also manage the transaction through the back stack, which allows the user to manage it through the activity, which lets users navigate to the state they were in before the change (like the activity return stack).

A transaction consists of a set of operations at the same time. We can use add() , remove() replace() 1 or more of them to complete a transactional operation. Finally, the method needs to be called to commit() complete the transaction submission.

Before calling commit() , we may need to call addToBackStack(String) (the parameter is the back stack name), which enables the transaction of the operation to be added to the back stack of the fragment transaction. The back stack is managed by the activity and can be returned to the fragment state before the change.

For example:

// 创建fragment和事务new ExampleFragment();FragmentTransaction transaction = getFragmentManager().beginTransaction();// 使用fragment替换id为fragment_container的视图// 将本次事务添加到back栈中transaction.replace(R.id.fragment_container, newFragment);transaction.addToBackStack(null);// 提交事务transaction.commit();

example, replace R.id.fragment_container with the Examplefragment object. It is then called to addToBackStack() Save the replacement transaction to the back stack. The user can return to the state before the replacement by the back key.

If multiple operations are performed in a single transaction and then invoked addToBackStack() , all commit() previous operations are saved in the back stack and served as a single transaction.

There are two points to note:

    1. Must be called after a transaction operation is completed commit() ;
    2. If you add multiple fragment to a layout, the order in which they are displayed is the same as the order in which they were added.

When we remove a fragment, if not called addToBackStack() , the fragment will be destroyed when the transaction is removed and the user cannot return to the pre-removal state. If it is called, when a fragment is removed, the fragment enters the stop state, and if the user navigates back, the fragment is restarted.

Tip

    1. For each transaction, we can setTransaction() animate the transaction by setting the method before it is commit() called.
    2. Can be called to hide(Fragment) hide the current fragment, simply set to invisible and not destroyed; The call show(Fragment) shows the hidden fragment. Of course, these two operations are also transactions and must be commit() executed before the call.

The call commit() does not execute the transaction immediately, but instead adds the transaction to the main thread's task table, which executes when the main thread is able to process it. We can immediately execute a method-committed transaction by calling the Fragmentmanager method executePendingTransactions() commit() , which must be executed in the main thread. In general, it is not necessary to do this, only if other threads need to rely on the transaction.

Note: The commit() method needs to be called before the activity is saved, otherwise it throws an exception. This is because if the activity recovers data, the state after the method is committed may be lost. If the data is allowed to be lost, we can call commitAllowingStateLoss() instead of calling commit() .

and activity Communication

Although fragment is an activity-independent object and can use the same fragment in multiple activities, we can still communicate directly with the fragments it contains in the activity.

In fragment, you can getActivity() get activity through methods, and then you can communicate, such as getting controls in the activity layout:

View listView = getActivity().findViewById(R.id.list);

Similarly, activity can be used Fragmentmanager findFragmentById() or findFragmentByTag() get fragment, for example:

ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);

There are two ways to set and get saved bundle objects in fragment: setArgument() and getArgument() .

To create an event callback method

In some cases, fragment may need to share events with the host activity. A good idea is to define a callback interface in fragment, and the host activity implements that interface. When activity receives callbacks through an interface, he can share information with other fragments if necessary.

For example, the news app, which contains two fragments, one for displaying the article title list (fragment a) and the other for displaying the article content (fragment B). When you click on an article title in the title list in a, you need to display the article's details in B. Therefore, you need to define an interface in a OnArticleSelectedListener :

publicstaticclass FragmentA extends ListFragment {    ...    // Container Activity must implement this interface    publicinterface OnArticleSelectedListener {        publicvoidonArticleSelected(Uri articleUri);    }    ...}

Then, the host activity needs to implement the interface and implement it to onArticleSelected(Uri articleUri) notify B to display the specific content event. To ensure that the interface is implemented in the host activity, you can onAttach() cast the host activity in fragment to instantiate the interface. For example:

 Public Static  class fragmenta extends listfragment {Onarticleselectedlistener Mlistener; ...@Override     Public void Onattach(Activity activity) {Super. Onattach (activity);Try{Mlistener = (onarticleselectedlistener) activity; }Catch(ClassCastException e) {Throw NewClassCastException (activity.tostring () +"must implement Onarticleselectedlistener"); }    }    ...}

You can see that the classcastexception exception is thrown if the host activity does not implement the interface. If implemented, then the Mlistener variable holds a reference to the host activity, and a can implement a shared click event through an interface method. For example, suppose a inherits from Listfragment, which is called every time the user taps the list option, and onListItemClick() we can callback the interface method here:

public  static  class  fragmenta  extends  listfragment  { Onarticleselectedlistener Mlistener; ...  @Override  public  void  onlistitemclick  (ListView L, View V, int  position, long  ID) {//Append the clicked item ' s row ID with the content provider URI  URI No Teuri = Contenturis.withappendedid (Articlecolumns.content_uri, id); //Send the event and Uri to the host activity  mlistener.onarticleselected (noteur i); } ...} 

onListItemClick()The ID parameter passed in is the line number of the option being clicked (content from ContentProvider).

About Contentproviders can refer to my previous translation of the article:
Unscramble android ContentProvider (1) CRUD operations and interpret Android ContentProvider (2) to create your own provider.

Add to Actionbar option

Fragments can be used as a menu option in the Options menu (and therefore also actionbar) of the activity by implementing fragment onCreateOptionsMenu() . To callback the method, it must be onCreate() called in setHasOptionsMenu() , indicating that the fragment is a menu option.

Any options added through fragments will be appended to the existing Options menu. The callback occurs when an option is clicked onOptionsItemSelected() .

We can also registerForContextMenu() provide a context menu by registering a view in the fragment layout. Called when the user opens the context menu onCreateContextMenu() . Called when the user selects an option onContextItemSelected() .

Note: Although fragment receives a click option callback method when the user chooses an option, the activity first callbacks the corresponding method. If the selected option is not implemented in the activity, the event is passed to the callback method of fragment. This is true for both the context menu and the Options menu.

Process the Fragment life cycle

The life cycle of the fragment is similar to the activity's life cycle, and there are three states:

    • Resumed
      Running state. The fragment is visible in the active activity.
    • Paused
      Another activity comes to the foreground and gets the focus, but the host activity is still visible (covered by transparent or dialog-style activity).
    • Stopped
      Fragment is no longer visible. Either the host activity is in a stopped state or the fragment is removed but added to the back stack. The fragment in the stopped state remains alive (all state information and members are saved by the system). If the host activity is killed, it is no longer available and will be killed.

As with activity, we can also save the fragment state through the bundle object when the process where the host activity is killed, and then restore the fragment state when the activity is rebuilt. We can save the state in the fragment, onSaveInstanceState() in onCreate() , or onCreateView() , or onActivityCreated() restore the data.

An important difference between the activity and the fragment life cycle is how to save it in the back stack. By default, activity is placed in the back stack of activities, and the back stack is managed by the system. However, fragment's back stack is managed by the host activity, and when fragment is removed only if we addToBackStack() add the fragment to the back stack explicitly. That is to say fragment to enter the back stack must meet two conditions:
1. The fragment will be removed;
2. commit() must be called before addToBackStack() .

The life cycle of the fragment is similar to the activity's life cycle, and we need to pay particular attention to how the life cycle of the activity affects the fragment life cycle.

Note: If we need to get a context object in fragment, we can pass getActivity() . However, this method can only be used if the fragment is associated with acitivity. The method returns NULL when fragment is not associated with activity or disassociate.

Coordinate with the activity life cycle

The life cycle of the host activity directly affects the life cycle of the fragment, so each periodic method of activity results in a similar fragment cycle method.

In addition, fragment has some other cycle methods, as follows:

    • onAttach()
      Called when fragment is associated with an activity, and the activity parameter is passed.
    • onCreateView()
      Called when the Fragment view hierarchy is created.
    • onActivityCreated()
      Called when the activity method onCreate() returns.
    • onDestroyView()
      Called when the fragment view is removed.
    • onDetach()
      Called when fragment is associated with activity.

Describes how the host activity affects fragment:

It is only when the host activity is running that we can handle the fragment life cycle independently. Otherwise, it will be affected by the host activity as shown.

Interpreting Android's Fragment

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.