Android - Fragments
Android - Fragments
Section titled “Android - Fragments”A Fragment represents a reusable portion of your application’s UI or behavior within an Activity. You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running.
Key characteristics and benefits of using Fragments:
- Modularity: Fragments allow you to break down your Activity’s UI and logic into self-contained, reusable components.
- Adaptable UIs: You can combine multiple fragments in a single activity to build a multi-pane UI (e.g., for tablets) and reuse those same fragments individually for single-pane UIs (e.g., for handsets).
- Lifecycle: A fragment has its own lifecycle, which is closely tied to the lifecycle of its host
Activity. When the activity is paused, all fragments within it are also paused, and so on. - Reusability: A fragment can be used in multiple activities.
- Headless Fragments: Fragments don’t necessarily need to have a UI. You can create headless fragments to encapsulate background behavior or data processing tied to an Activity’s lifecycle.
- Integration with Modern Android Jetpack: Fragments are a core part of Android Jetpack, integrating well with components like
ViewModel,LiveData, and the Navigation Component.
You create fragments by extending the androidx.fragment.app.Fragment class. You can then insert a fragment into your activity’s layout either declaratively in the XML layout file using the <fragment> tag or programmatically using FragmentManager and FragmentTransaction.
Use Case: Adaptive UI
Section titled “Use Case: Adaptive UI”Imagine an application that displays a list of articles. On a handset, selecting an article might navigate to a new screen (Activity) to show the article’s content. On a tablet, due to more screen real estate, the list of articles could be in one fragment on the left, and the selected article’s content could be displayed in another fragment on the right, all within the same Activity. Fragments make this kind of adaptive design much easier to implement.
Fragment Lifecycle
Section titled “Fragment Lifecycle”A fragment’s lifecycle is directly affected by its host Activity’s lifecycle. For example, when the activity receives onPause(), each fragment in the activity receives onPause().
Here are the key lifecycle callback methods you can override in your Fragment class (from androidx.fragment.app.Fragment):
onAttach(Context context): Called when the fragment has been associated with an activity (theActivityis passed in here, though it’s safer to usecontext). This is called beforeonCreate().onCreate(Bundle savedInstanceState): The system calls this when creating the fragment. You should initialize essential components of the fragment that you want to retain when the fragment is paused or stopped, then resumed. This is a good place to initializeViewModels.onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState): The system calls this when it’s time for the fragment to draw its user interface for the first time. You must return aViewfrom this method that is the root of your fragment’s layout. You can returnnullif the fragment does not provide a UI. This is where you inflate your layout XML.onViewCreated(View view, Bundle savedInstanceState): Called immediately afteronCreateView()has returned, but before any saved state has been restored into the view. This is where you should set up your views (e.g., find views by ID, set up listeners, observeLiveData).onStart(): Called when the fragment is visible to the user (its activity has been started).onResume(): Called when the fragment is visible and actively running (its activity has been resumed). The fragment can now interact with the user.onPause(): The system calls this method as the first indication that the user is leaving the fragment (though it does not always mean the fragment is being destroyed). This is usually where you should commit any changes that should be persisted beyond the current user session (e.g., save user input).onStop(): Called when the fragment is no longer visible to the user. This may happen because the activity is being stopped or a new fragment is covering it.onDestroyView(): Called when the view hierarchy associated with the fragment is being removed. This is where you should clean up resources associated with the fragment’s view (e.g., clear references to views to prevent memory leaks).onDestroy(): Called to do final cleanup of the fragment’s state. This is called when the fragment is no longer in use. Not guaranteed to be called if the process is killed.onDetach(): Called when the fragment is being disassociated from the activity. This is the counterpart toonAttach().
How to Use Fragments?
Section titled “How to Use Fragments?”Implementing fragments involves a few key steps:
- Define the Fragment Class: Create a class that extends
androidx.fragment.app.Fragment. Implement necessary lifecycle callbacks, especiallyonCreateView()to provide the fragment’s layout. - Create the Fragment’s Layout: Design an XML layout file for the fragment’s UI.
- Add the Fragment to an Activity: You can do this in two ways:
- Manage Fragment Transactions: Use
getSupportFragmentManager()(fromFragmentActivityorAppCompatActivity) to begin transactions for adding, replacing, or removing fragments.
Example: Adding a Fragment Dynamically
Section titled “Example: Adding a Fragment Dynamically”Let’s create a simple example where an Activity dynamically loads a Fragment into a container.
- Create
MyFragment.java:
package com.example.fragmentapp;
import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import androidx.annotation.NonNull;import androidx.annotation.Nullable;import androidx.fragment.app.Fragment;
public class MyFragment extends Fragment {
private static final String ARG_MESSAGE = "message";
public static MyFragment newInstance(String message) { MyFragment fragment = new MyFragment(); Bundle args = new Bundle(); args.putString(ARG_MESSAGE, message); fragment.setArguments(args); return fragment; }
@Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_my, container, false); }
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); TextView textView = view.findViewById(R.id.fragment_textview); if (getArguments() != null) { String message = getArguments().getString(ARG_MESSAGE); textView.setText(message != null ? message : "Hello from MyFragment!"); } }}- Create layout
res/layout/fragment_my.xml:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" android:padding="16dp" android:background="#E0E0E0">
<TextView android:id="@+id/fragment_textview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" android:text="Hello from MyFragment!" />
</LinearLayout>- Modify
MainActivity.javaandres/layout/activity_main.xml:
res/layout/activity_main.xml:
<?xml version="1.0" encoding="utf-8"?><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">
<androidx.fragment.app.FragmentContainerView android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" />
<Button android:id="@+id/button_load_fragment" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Load Fragment" />
</LinearLayout>MainActivity.java:
package com.example.fragmentapp;
import androidx.appcompat.app.AppCompatActivity;import androidx.fragment.app.FragmentManager;import androidx.fragment.app.FragmentTransaction;
import android.os.Bundle;import android.widget.Button;
public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
Button loadFragmentButton = findViewById(R.id.button_load_fragment); loadFragmentButton.setOnClickListener(v -> { loadFragment(); });
// Optionally load fragment initially if (savedInstanceState == null) { // Ensure fragment is added only once loadFragmentWithMessage("Initial Fragment Load"); } }
private void loadFragment() { loadFragmentWithMessage("Fragment Loaded by Button"); }
private void loadFragmentWithMessage(String message) { // Create an instance of the fragment MyFragment myFragment = MyFragment.newInstance(message);
// Get the FragmentManager and start a transaction FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// Replace whatever is in the fragment_container view with this fragment, // and add the transaction to the back stack so the user can navigate back fragmentTransaction.replace(R.id.fragment_container, myFragment); fragmentTransaction.addToBackStack(null); // Optional: if you want back navigation
// Commit the transaction fragmentTransaction.commit(); }}Modern Fragment Practices
Section titled “Modern Fragment Practices”- Use
androidx.fragment.app.FragmentContainerViewas the container for dynamically added fragments. It offers better handling of fragment animations and z-ordering. - Pass arguments to fragments using a
BundleviaFragment.setArguments(Bundle). Use a staticnewInstance()factory method within the fragment class to encapsulate argument creation. - Communicate between fragments and activities using
ViewModels andLiveData(orFlowwith Kotlin). This decouples components and handles lifecycle complexities. - Use the Navigation Component for managing fragment navigation and passing data between destinations. It simplifies complex navigation graphs.
- For simple dialogs, use
DialogFragment. - Ensure you are using the
androidx.fragmentlibrary, not the deprecated platform version.
Fragments are a powerful tool for building flexible and adaptive Android UIs. Mastering their lifecycle and interaction patterns is key to developing robust Android applications.