Android - Fragment
Android - Fragments
Section titled “Android - Fragments”一个 Fragment 代表应用 UI 或行为中可重用的部分,位于 Activity 内部。你可以将 Fragment 视为 Activity 的一个模块化部分,它拥有自己的生命周期,接收自己的输入事件,并且可以在 Activity 运行时添加或移除。
使用 Fragment 的主要特点和优势:
- 模块化(Modularity):Fragment 允许你将 Activity 的 UI 和逻辑分解为独立的、可重用的组件。
- 自适应 UI(Adaptable UIs):你可以在单个 Activity 中组合多个 Fragment 来构建多窗格 UI(例如,用于平板电脑),并为单窗格 UI(例如,用于手机)单独重用这些相同的 Fragment。
- 生命周期(Lifecycle):Fragment 有自己的生命周期,它与宿主
Activity的生命周期紧密相关。当 Activity 暂停时,其中的所有 Fragment 也会暂停,依此类推。 - 可重用性(Reusability):一个 Fragment 可以在多个 Activity 中使用。
- 无 UI Fragment(Headless Fragments):Fragment 不一定需要有 UI。你可以创建无 UI Fragment 来封装与 Activity 生命周期绑定的后台行为或数据处理。
- 与现代 Android Jetpack 集成:Fragment 是 Android Jetpack 的核心部分,与
ViewModel、LiveData和 Navigation Component 等组件良好集成。
通过扩展 androidx.fragment.app.Fragment 类来创建 Fragment。然后,你可以通过在 XML 布局文件中使用 <fragment> 标签(已弃用,推荐使用 <androidx.fragment.app.FragmentContainerView>)声明式地将 Fragment 插入到 Activity 的布局中,或者通过 FragmentManager 和 FragmentTransaction 以编程方式进行操作。
使用场景:自适应 UI
Section titled “使用场景:自适应 UI”想象一个显示文章列表的应用。在手机上,选择一篇文章可能会导航到一个新屏幕(Activity)来显示文章内容。在平板电脑上,由于屏幕空间更大,文章列表可以在左侧的一个 Fragment 中,而所选文章的内容可以在右侧的另一个 Fragment 中显示,所有这些都在同一个 Activity 中。Fragment 使这种自适应设计更容易实现。
Fragment 生命周期
Section titled “Fragment 生命周期”Fragment 的生命周期直接受其宿主 Activity 生命周期影响。例如,当 Activity 接收到 onPause() 时,Activity 中的每个 Fragment 也会接收到 onPause()。
以下是你可以在 Fragment 类中重写的关键生命周期回调方法(来自 androidx.fragment.app.Fragment):
onAttach(Context context): Fragment 与 Activity 关联时调用(Activity 在此处通过context传递,使用context更安全)。在onCreate()之前调用。onCreate(Bundle savedInstanceState): 系统在创建 Fragment 时调用此方法。你应该在此初始化 Fragment 中需要保留的关键组件,以便在 Fragment 暂停或停止后恢复时使用。这是初始化ViewModel的好地方。onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState): 系统在 Fragment 首次绘制其用户界面时调用此方法。你必须从此方法返回一个View,作为 Fragment 布局的根视图。如果 Fragment 不提供 UI,可以返回null。你在此处加载(inflate)你的布局 XML。onViewCreated(View view, Bundle savedInstanceState): 在onCreateView()返回后立即调用,但在任何保存的状态恢复到视图之前。你应在此设置视图(例如,通过 ID 查找视图,设置监听器,观察LiveData)。onStart(): 当 Fragment 对用户可见时调用(其所在的 Activity 已启动)。onResume(): 当 Fragment 可见并正在积极运行时调用(其所在的 Activity 已恢复)。Fragment 现在可以与用户交互。onPause(): 系统调用此方法作为用户离开 Fragment 的首个指示(尽管这并不总是意味着 Fragment 将被销毁)。通常,你应在此处提交任何应在当前用户会话结束后持久化的更改(例如,保存用户输入)。onStop(): 当 Fragment 对用户不再可见时调用。这可能是因为 Activity 正在停止或有新的 Fragment 覆盖了它。onDestroyView(): 当与 Fragment 关联的视图层次结构被移除时调用。你应在此清理与 Fragment 视图关联的资源(例如,清除对视图的引用以防止内存泄漏)。onDestroy(): 调用此方法进行 Fragment 状态的最终清理。在 Fragment 不再使用时调用。如果进程被终止,不保证会调用此方法。onDetach(): Fragment 与 Activity 解除关联时调用。这是onAttach()的对应方法。
如何使用 Fragment?
Section titled “如何使用 Fragment?”实现 Fragment 需要几个关键步骤:
- 定义 Fragment 类:创建一个扩展
androidx.fragment.app.Fragment的类。实现必要的生命周期回调,特别是onCreateView()以提供 Fragment 的布局。 - 创建 Fragment 的布局:为 Fragment 的 UI 设计一个 XML 布局文件。
- 将 Fragment 添加到 Activity:你可以通过两种方式完成此操作:
- 管理 Fragment 事务:使用
getSupportFragmentManager()(来自FragmentActivity或AppCompatActivity)开始添加、替换或移除 Fragment 的事务。
示例:动态添加 Fragment
Section titled “示例:动态添加 Fragment”让我们创建一个简单示例,其中 Activity 动态地将一个 Fragment 加载到一个容器中。
- 创建
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!"); } }}- 创建布局
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>- 修改
MainActivity.java和res/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(); }}现代 Fragment 实践
Section titled “现代 Fragment 实践”- 使用
androidx.fragment.app.FragmentContainerView作为动态添加 Fragment 的容器。它提供更好的 Fragment 动画和 Z 轴顺序处理。 - 使用
Bundle通过Fragment.setArguments(Bundle)将参数传递给 Fragment。在 Fragment 类内部使用静态newInstance()工厂方法封装参数创建过程。 - 使用
ViewModel和LiveData(或 Kotlin 的Flow)在 Fragment 和 Activity 之间进行通信。这可以解耦组件并处理生命周期复杂性。 - 使用 Navigation Component 管理 Fragment 导航并在目的地之间传递数据。它简化了复杂的导航图。
- 对于简单的对话框,使用
DialogFragment。 - 确保你使用的是
androidx.fragment库,而不是已弃用的平台版本。
Fragment 是构建灵活和自适应 Android UI 的强大工具。掌握其生命周期和交互模式是开发健壮的 Android 应用的关键。