Why Fragment? What is the relationship between Fragment and Activity? What is the Fragment lifecycle? How does Fragment work? In fact, Fragment is a UI Fragment that can be embedded in activities, which can make programs make more reasonable and full use of the space of the large screen. It was originally developed to adapt to tablet computers with large screens. It can be regarded as a small Activity, also known as an Activity Fragment. Here’s a look at some of the wonders of fragments

Fragment Overview

Using fragments, you can divide the screen into several pieces and then group them for a modular management. Fragments cannot be used alone. They need to be nested within an Activity, and their life cycle is also affected by the life cycle of the host Activity.

1. An Activity can run multiple Fragments

2. Fragment cannot exist without an Activity

3. The Activity is the body of the screen, and the Fragment is a component of the Activity

4. A Fragment can be reused by multiple activities

Fragments have their own life cycle and can receive input events

6. You can dynamically add or remove fragments while your Activity is running

Advantages of Fragments:

Modularity: Instead of writing all of your code in your Activity, write it in its own Fragment.

2. Reusability: Multiple activities can reuse a Fragment.

3, adaptable: according to the hardware screen size, screen direction, can easily achieve different layouts, so that the user experience is better.

Static and dynamic loading

There are two ways to use fragments: static loading and dynamic loading.

1. Static loading

The process for static loading is as follows:

  • Define the Fragment XML layout file
  • Create a custom Fragment class that inherits the Fragment class or one of its subclasses and implements the onCreate() method, in which the layout file is loaded through inflater.inflate and its View is returned
  • Set the name attribute in the layout file corresponding to the Activity that needs to load a Fragment to the fully qualified class name, that is, the package name. Fragment
  • Finally, the Activity calls setContentView() to load the layout file

Static loading, once added, cannot be removed at run time

For example, I now want to enter an Activity that is dedicated to static loading

Public void toStaticLoadActivity(View View) {startActivity(new Intent(MainActivity. This, StaticLoadActivity.class)); }Copy the code

The StaticLoadActivity layout file looks like this:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/list_fragment"
        android:name="com.example.learnfragment.ListFragment"
        android:layout_width="250dp"
        android:layout_height="150dp"/>

    <fragment
        android:layout_marginTop="20dp"
        android:id="@+id/list_fragment_two"
        android:name="com.example.learnfragment.ListFragment"
        android:layout_width="250dp"
        android:layout_gravity="center"
        android:layout_height="150dp"/>
</LinearLayout>
Copy the code

Fragments of the name attribute points to the com. Example. Learnfragment. ListFragment:

ListFragment public class ListFragment extends Fragment {@nullable @override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_list, container, false); TextView textView = view.findViewById(R.id.tv_static_load); textView.setText("Hello, Fragment!" ); return view; }}Copy the code

The fragment_list.xml layout file looks like this:


<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:background="@color/colorPrimary"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv_static_load"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:gravity="center"
        android:textColor="#ffffff"
        android:textSize="20sp"
        android:text="This is a fragment" />
</LinearLayout>
Copy the code

Now just click on the TextView in the Main Activity to see the effect of a statically loaded Fragment:

The Fragment is reusable because the StaticLoadActivity layout file contains two Fragment tags.

2. Dynamic loading

The process for dynamically loading fragments is as follows:

  • Prepare containers, or containers for fragments, in advance
  • Through get FragmentManager getSupportFragmentManager ()
  • Get the FragmentTransaction object from fm.beginTransaction()
  • Call the add() or repalce() method to load the Fragment
  • Finally, the commit() method is called to commit the transaction

To demonstrate the dynamic loading of fragments, prepare two containers and buttons in the activity_main. XML layout file:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <TextView android:layout_width="match_parent" android:layout_height="100dp" android:gravity="center" android:onClick="toStaticLoadActivity" android:text="static load fragment" /> <LinearLayout android:layout_width="match_parent" android:orientation="horizontal" android:layout_height="wrap_content"> <Button Android :id="@+id/load_left" Android :text=" load left" Android :layout_width="0dp" Android :layout_weight="1" android:onClick="dynamicLoad" android:layout_height="wrap_content"/> <Button android:id="@+id/load_right" Android :text=" load right "Android :layout_width="0dp" Android :layout_weight="1" Android :onClick="dynamicLoad" <Button android:id="@+id/remove_left" Android :text=" left" android:layout_width="0dp" android:layout_weight="1" android:onClick="dynamicLoad" <Button android:id="@+id/remove_right" Android :text=" delete right" android:layout_width="0dp" android:layout_weight="1" android:onClick="dynamicLoad" android:layout_height="wrap_content"/> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_margin="1dp" android:id="@+id/list_container" android:layout_width="150dp" android:orientation="horizontal" android:layout_height="400dp"> </LinearLayout> <LinearLayout android:layout_margin="1dp" android:orientation="horizontal" android:id="@+id/detail_container" android:layout_width="200dp" android:layout_height="400dp"> </LinearLayout> </LinearLayout> </LinearLayout>Copy the code

One Container is list_container and the other is detail_container. The click events of the four buttons are dynamicLoad respectively:

public class MainActivity extends AppCompatActivity { ListFragment leftFragment = null; ListFragment rightFragment = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Public void toStaticLoadActivity(View View) {startActivity(new Intent(mainActivity.this, StaticLoadActivity.class)); Container 2, fragment 3, fragment -> container public void dynamicLoad(View View) {int id = view.getid (); switch (id){ case R.id.load_left: leftFragment = new ListFragment(); getSupportFragmentManager() .beginTransaction() .add(R.id.list_container, leftFragment) .commit(); break; case R.id.load_right: rightFragment = new ListFragment(); getSupportFragmentManager() .beginTransaction() .add(R.id.detail_container, rightFragment) .commit(); break; case R.id.remove_left: getSupportFragmentManager() .beginTransaction() .remove(leftFragment) .commit(); break; case R.id.remove_right: getSupportFragmentManager() .beginTransaction() .remove(rightFragment) .commit(); break; }}}Copy the code

Dynamic loading fragments, add and remove operations such as FragmentTransaction class provides a method to finish, after the completion of calls to FragmentTransaction.com MIT commit changes () method.

  • Transaction.add () : Adds a fragment to the Activity

  • Transaction.remove () : Removes a Fragment from an Activity. If the removed Fragment is not added to the rollback stack, the Fragment instance will be destroyed

  • Transaction.replace () : Replaces the current Fragment with another Fragment, which is essentially a combination of remove() and then add()

  • Transaction. Hide () : Hides the current Fragment from view and will not be destroyed

  • Transaction.show () : Displays previously hidden fragments

  • Detach () : Removes the view from the UI, unlike remove(), where the fragment state is still maintained by the FragmentManager

  • Attach () : Rebuilds the view, attaches it to the UI and displays it.

The Commit method for FragmentTransaction must be called before activity.onsaveInstance (). The commit() operation is asynchronous and internally queued for processing via mManager.enqueueAction(). CommitNow () : checkStateLoss() : checkStateLoss() : checkStateLoss() : checkStateLoss() : checkStateLoss() : checkStateLoss() : checkStateLoss() The commitAllowingStateLoss() method is a commit() method that doesn’t throw the exception version, but try to use commit() instead of commitAllowingStateLoss().

FragmentManager has a BackStack, similar to an Activity’s task stack. If this statement is added, the transaction is added to the BackStack. When the user clicks the back button, the transaction is rolled back. The rollback is remove(frag1)); If this statement is not added, clicking the back button destroys the Activity directly.

3. Use attention points

The onCreateView() method of the Fragment returns the UI layout of the Fragment. Note that the third argument to the inflate() is false, because inside the Fragment implementation the layout is added to the container. If set to true, The addition is repeated twice, and IllegalStateException is thrown.

2. If you’re passing in parameters when you create a Fragment, you must add them through setArguments(Bundle Bundle). It’s not recommended to add constructors with parameters to the Fragment, because adding them through setArguments(), This data can be retained if the Fragment is re-instantiated by the system due to memory constraints.

3. You can get the parameters passed in by getArguments() in the Fragment onAttach(). To get an Activity object, instead of calling getActivity(), it is recommended to force the Context object into an Activity object in onAttach().

The Activity sends a value to the Fragment

Write a method to get a ListFragment in ListFragment:

public class ListFragment extends Fragment { private static final String BUNDLE_TITTLE = "bundle_tittle"; private String mTittle; Public static ListFragment getInstance(String tittle){ListFragment fragment = new ListFragment(); Bundle bundle = new Bundle(); bundle.putString(BUNDLE_TITTLE, tittle); fragment.setArguments(bundle); return fragment; } / /... @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle arguments = getArguments(); if(arguments ! = null){ mTittle = arguments.getString(BUNDLE_TITTLE); }} @nullable @override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_list, container, false); TextView textView = view.findViewById(R.id.tv_static_load); textView.setText(mTittle); return view; }}Copy the code

When creating a ListFragment object, pass the listFragment.getInstance () parameter directly:

switch (id){ case R.id.load_left: leftFragment = ListFragment.getInstance("Left Fragment!" ); getSupportFragmentManager() .beginTransaction() .add(R.id.list_container, leftFragment) .commit(); break; case R.id.load_right: rightFragment = ListFragment.getInstance("Right Fragment!" ); getSupportFragmentManager() .beginTransaction() .add(R.id.detail_container, rightFragment) .commit(); break; / /... }Copy the code

Fragment sends a value to the Activity

Following the example above, first define it in the ListFragment

public class ListFragment extends Fragment { ...... @nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_list, container, false); TextView textView = view.findViewById(R.id.tv_static_load); textView.setText(tittle); textView.setOnClickListener((v) -> { if(mOnTittleListener ! = null) { mOnTittleListener.onClick(tittle); }}); return view; Public interface OnTittleListener {void onClick(String Tittle); } private OnTittleListener mOnTittleListener; Public void setOnTittleListener(OnTittleListener OnTittleListener) {this.montittLelistener = onTittleListener; }}Copy the code

In the MainActivity:

public class MainActivity extends AppCompatActivity implements ListFragment.OnTittleListener { ListFragment leftFragment  = null; boolean leftDisplay = false; . @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Container 2, fragment 3, fragment -> container leftFragment = ListFragment. GetInstance ("Left fragment!") ); getSupportFragmentManager() .beginTransaction() .add(R.id.list_container, leftFragment) .commit(); leftDisplay = true; leftFragment.setOnTittleListener(this); } @override public void tittle (String tittle) {Override public void tittle (String tittle) { }}Copy the code

If the Context is needed in fragments, can pass getActivity (), if the Context need to exist after the Activity is destroyed, then use getActivity. GetApplicationContext (); Consider reusing a Fragment to reduce coupling with an Activity. The Fragment operation should be up to the Activity that manages it.

Fragment life cycle

Lifecycle methods commonly used in Fragments

There are lifecycle methods for fragments from creation to runtime callback

OnAttach (): method called when the Fragment is attached to the Activity

2. OnCreate (): method called when Fragment is created

3, onCreateView(): method called when loading the Fragment layout

4. OnActivityCreated (): method called when the Activity attached to the Fragment is created

5, onStart(): method called when Fragment is started

6, onResume(): method called while the Fragment is running

Lifecycle method called when the Fragment is no longer in use

7, onPause(): this method is called when the Fragment is not interacting

8, onStop(): this method is called when the Fragment is no longer visible

OnDestroyView (): method called when destroying the Fragment layout

OnDestroy (): method called when an Frament is destroyed

11. OnDetach (): method called when the Fragment is completely out of the Activity

The Fragment lifecycle is shown in code below:

The layout of MainActivity has two buttons, one for loading the Fragment and the other for switching to another Activity. The interface code of MainActivity is shown as follows:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" <Button android:onClick="loadFragment" android:text=" loadFragment" android:text=" loadFragment" android:textAllCaps="false" android:layout_width="match_parent" android:layout_height="wrap_content"/> <Button Android :layout_width="match_parent" Android :layout_height="wrap_content" Android :text=" Switch to another Activity" android:textAllCaps="false" android:onClick="toAnotherActivity" /> <LinearLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="0dp" android:orientation="vertical" android:layout_weight="2"  /> </LinearLayout>Copy the code

MyFragment interface:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MyFragment"> <TextView android:gravity="center" android:layout_marginTop="50dp" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" Android :text="Fragment layout display "/> </RelativeLayout>Copy the code

AnotherActivity interface:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".AnotherActivity"> <TextView android:layout_centerInParent="true" android:layout_width="match_parent" Android :gravity="center" Android :textAllCaps="false" Android :layout_height="match_parent"/>  </RelativeLayout>Copy the code

MainActivity’s logic is basically two click events:

public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } // loadFragment public void loadFragment(View View) {MyFragment Fragment = myfragment.newinstance (); getSupportFragmentManager() .beginTransaction() .add(R.id.container, fragment, "MyFragment") .commit(); Public void toAnotherActivity(View View) {startActivity(new Intent(this, anotherActivity.class)); }}Copy the code

MyFragment code is as follows:

public class MyFragment extends Fragment { private static final String TAG = "MyFragment"; public static MyFragment newInstance() { return new MyFragment(); } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log. I (TAG, "onCreate: Fragment "); } @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @nullable Bundle savedInstanceState) {log. I (TAG, "onCreateView: Fragment "); return inflater.inflate(R.layout.my_fragment, container, false); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Log. I (TAG, "onActivityCreated: Attached Activity created "); } @Override public void onStart() { super.onStart(); Log. I (TAG, "onStart: Fragment "); } @Override public void onResume() { super.onResume(); Log. I (TAG, "onResume: Fragment running "); } @Override public void onPause() { super.onPause(); Log. I (TAG, "onPause: Fragment "); } @Override public void onStop() { super.onStop(); Log. I (TAG, "onStop: Fragment "); } @Override public void onDestroyView() { super.onDestroyView(); Log. I (TAG, "onDestroyView: Fragment Destruction "); } @Override public void onDestroy() { super.onDestroy(); Log. I (TAG, "onDestroy: Fragment destroy "); } @Override public void onDetach() { super.onDetach(); Log. I (TAG, "onDetach: Fragment from Activity"); }}Copy the code

Through the demo, you can see the following effects:

10 to 18 17:18:08. 735. 5107-5107 / cn changlin. Fragmentlifecycle I/MyFragment: onCreate: Fragments to create 10 to 18 17:18:08. 736. 5107-5107 / cn changlin. Fragmentlifecycle I/MyFragment: onCreateView: 10 to 18 17:18:08 fragments binding layout. 742. 5107-5107 / cn changlin. Fragmentlifecycle I/MyFragment: onActivityCreated: Attached the Activity to create 10 to 18 17:18:08. 742. 5107-5107 / cn changlin. Fragmentlifecycle I/MyFragment: onStart: Fragments start 10 to 18 17:18:08. 742. 5107-5107 / cn changlin. Fragmentlifecycle I/MyFragment: onResume: Fragments are running 10 to 18 17:18:11. 353. 5107-5107 / cn changlin. Fragmentlifecycle I/MyFragment: onPause: Fragments are no longer interaction 10 to 18 17:18:11. 820. 5107-5107 / cn changlin. Fragmentlifecycle I/MyFragment: onStop: Stop running fragments 10 to 18 17:18:14. 072, 5107-5107 / cn. Changlin. Fragmentlifecycle I/MyFragment: onStart: Fragments start 10 to 18 17:18:14. 072. 5107-5107 / cn changlin. Fragmentlifecycle I/MyFragment: onResume: Fragments are running 10 to 18 17:18:16. 221. 5107-5107 / cn changlin. Fragmentlifecycle I/MyFragment: onPause: Fragments are no longer interaction 10 to 18 17:18:16. 606. 5107-5107 / cn changlin. Fragmentlifecycle I/MyFragment: onStop: Stop running fragments 10 to 18 17:18:16. 607, 5107-5107 / cn. Changlin. Fragmentlifecycle I/MyFragment: onDestroyView: Fragments view destroy 10 to 18 17:18:16. 619. 5107-5107 / cn changlin. Fragmentlifecycle I/MyFragment: onDestroy: Fragments destroy 10 to 18 17:18:16. 619. 5107-5107 / cn changlin. Fragmentlifecycle I/MyFragment: onDetach: fragments from the ActivityCopy the code