当前位置: 首页 > news >正文

掌握Android Fragment开发之魂:Fragment的深度解析(上)


Fragment是Android开发中用于构建动态和灵活界面的基石。它不仅提升了应用的模块化程度,还增强了用户界面的动态性和交互性,允许开发者将应用界面划分为多个独立、可重用的部分,每个部分都可以独立于其他部分进行操作。本文将从以下几个方面深入探讨Fragment的核心特性、优势、生命周期,以及如何通过静态和动态添加来丰富你的应用。


一、Fragment的特点


Fragment是Android中非常强大和灵活的概念,它极大地简化了构建动态和可适应不同屏幕尺寸的复杂UI的过程。通过合理利用Fragment,您可以构建模块化、可重用和高效的Android应用程序。


以下是Fragment的一些主要特点:

  1. 模块化UI: Fragment允许您将UI分解为独立的模块化组件。每个Fragment都定义了自己的布局和行为,并且可以在活动中添加、删除或替换。这使得构建可重用的UI组件和适应不同屏幕尺寸变得更加容易。

  2. 生命周期管理: 与Activity类似,Fragment也有自己的生命周期。系统负责管理Fragment的生命周期,使您能够专注于编写代码而不必担心生命周期问题。Fragment的生命周期回调与Activity的生命周期回调类似,但Fragment的生命周期优先于托管它的Activity。

  3. 向后兼容性: 在旧版本的Android系统上,Fragment提供了一种模拟新UI模式的方法。即使在较旧的Android版本上,您也可以编写支持片段的应用程序。

  4. 动态UI: Fragment可以在运行时动态添加到Activity布局中。这为您提供了灵活性,可以根据不同的条件动态构建和改变UI。

  5. 嵌套Fragment: Fragment可以嵌套在另一个Fragment中,这为构建复杂的UI层次结构提供了极大的灵活性。

  6. 支持多窗格设计: Fragment非常适合在大屏幕设备(如平板电脑)上实现多窗格UI设计。您可以将不同的Fragment组合在一个Activity中,并根据设备方向和大小调整布局。

  7. 提高可重用性: Fragment可以在多个Activity之间共享和重用。这不仅提高了代码的可重用性,还减少了代码重复,从而提高了应用程序的可维护性。

  8. Fragment事务: Fragment事务允许您在Activity布局中添加、移除、替换和附加Fragment。您可以通过提交一系列Fragment事务来构建复杂的UI流程。

  9. 支持RetainInstance: Fragment可以在配置更改(如设备旋转)时保留其实例。这意味着您可以避免重新创建昂贵的对象,从而提高应用程序的性能和响应能力。

  10. 向后兼容库支持: Android提供了对旧版本系统的Fragment向后兼容库支持。即使在较旧的Android版本上,您也可以使用Fragment提供的大多数功能。


二、Fragment的生命周期

在这里插入图片描述


Fragment的生命周期与Activity紧密相关,但有自己的特点。了解Fragment的生命周期对于正确管理Fragment至关重要。

Android Fragment拥有自己的生命周期,类似于Activity的生命周期。Fragment的生命周期回调方法与Activity非常相似,但又有一些独特之处。下面是Fragment生命周期的详细介绍,并通过Java代码示例进行演示:


1、onAttach(Context)

当Fragment与Activity实例关联时调用。可以在此方法中获取Activity的引用,并执行一些初始化操作。

@Override
public void onAttach(@NonNull Context context) {super.onAttach(context);// 获取Activity引用并执行初始化操作
}

2、onCreate(Bundle)

在Fragment创建时调用。可以在此方法中初始化一些数据和状态。

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 初始化数据和状态
}

3、onCreateView(LayoutInflater, ViewGroup, Bundle)

创建并返回Fragment的视图层次结构。

@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_layout, container, false);// 初始化视图return view;
}

4、onViewCreated(View, Bundle)

在Fragment的视图层次结构创建完成后调用。可以在此方法中进行视图的初始化操作。

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);// 初始化视图
}

5、onActivityCreated(Bundle)

在Activity的onCreate方法执行完毕后调用。

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);// 执行一些与Activity相关的操作
}

6、onStart()

当Fragment变为可见状态时调用


7、onResume()

当Fragment开始交互时调用。


8、onPause()

当Fragment从交互状态切换到暂停状态时调用。可以在此方法中释放一些资源。


9、onStop()

当Fragment不再可见时调用。


10、onDestroyView()

在Fragment的视图层次结构被销毁时调用。


11、onDestroy()

在Fragment被销毁之前调用。可以在此方法中释放资源。


12、onDetach()

当Fragment与Activity实例分离时调用。


此外,Fragment还提供了一些额外的生命周期回调方法,用于处理保存和恢复实例状态:

13、onSaveInstanceState(Bundle)

当Fragment需要保存状态时调用。可以在此方法中保存数据。

@Override
public void onSaveInstanceState(@NonNull Bundle outState) {super.onSaveInstanceState(outState);// 保存数据
}

14、onViewStateRestored(Bundle)

在Fragment视图状态被恢复后调用。可以在此方法中恢复数据。

@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {super.onViewStateRestored(savedInstanceState);// 恢复数据
}

三、Fragment的使用方式


在 Android 应用程序中使用 Fragment 有几种常见的方式,包括静态添加、动态添加和使用 FragmentManager 进行事务管理。下面通过 Java 代码示例演示每种方式:


1、静态添加 Fragment


静态添加 Fragment 是指在 Activity 的布局文件中直接定义 Fragment。这种方式适用于在应用启动时就需要显示的 Fragment。


(1)、 创建Fragment布局文件

首先,我们需要为每个Fragment创建一个布局文件。

fragment_a.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"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Fragment A"android:textSize="24sp" /><Buttonandroid:id="@+id/btn_fragment_a"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Click Me" /></LinearLayout>
fragment_b.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"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Fragment B"android:textSize="24sp" /><Buttonandroid:id="@+id/btn_fragment_b"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Click Me" /></LinearLayout>

(2)、 创建Fragment类


接下来,我们需要创建两个Fragment类,每个类对应一个Fragment布局。

FragmentA.java
public class FragmentA extends Fragment {@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_a, container, false);Button btnFragmentA = view.findViewById(R.id.btn_fragment_a);btnFragmentA.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 处理按钮点击事件Toast.makeText(getActivity(), "Fragment A Button Clicked", Toast.LENGTH_SHORT).show();}});return view;}
}
FragmentB.java
public class FragmentB extends Fragment {@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_b, container, false);Button btnFragmentB = view.findViewById(R.id.btn_fragment_b);btnFragmentB.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 处理按钮点击事件Toast.makeText(getActivity(), "Fragment B Button Clicked", Toast.LENGTH_SHORT).show();}});return view;}
}

(3)、 在Activity布局中静态添加Fragment

现在,我们将在Activity的布局文件中静态添加两个Fragment。

activity_main.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="horizontal"><fragmentandroid:id="@+id/fragment_a"android:name="com.example.FragmentA"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1" /><fragmentandroid:id="@+id/fragment_b"android:name="com.example.FragmentB"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1" /></LinearLayout>

在上面的布局文件中,我们使用<fragment>标签来静态添加两个Fragment。android:name属性指定了Fragment的完全限定类名,android:id属性为每个Fragment提供了一个唯一的标识符。


(4)、MainActivity

最后,我们只需要创建一个空的MainActivity即可,因为所有的Fragment都已经在布局文件中静态添加了。

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}
}

当你运行这个应用程序时,你会看到两个Fragment并排显示在屏幕上,每个Fragment中都有一个按钮。点击这些按钮会显示相应的Toast消息。


静态添加Fragment是一种简单而直接的方式,适用于在应用启动时就需要显示Fragment的情况。但是,如果你需要动态添加、移除或替换Fragment,那么你需要使用FragmentManager来管理Fragment事务。


2、动态添加 Fragment

动态添加 Fragment 是指在运行时通过代码将 Fragment 添加到 Activity 的布局中。这种方式适用于根据用户交互或其他条件动态显示 Fragment。

我们将创建一个主Activity,其布局文件中包含一个容器用于显示Fragment。我们将定义两个Fragment,并使用FragmentManager在容器中进行Fragment的添加、替换和移除操作。

(1)、 创建Fragment布局文件

首先,我们需要为每个Fragment创建一个布局文件。

fragment_a.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"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Fragment A"android:textSize="24sp" /></LinearLayout>
fragment_b.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"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Fragment B"android:textSize="24sp" /></LinearLayout>

(2)、创建Fragment类

接下来,我们需要创建两个Fragment类,每个类对应一个Fragment布局。

FragmentA.java
public class FragmentA extends Fragment {@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_a, container, false);}
}
FragmentB.java
public class FragmentB extends Fragment {@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {return inflater.inflate(R.layout.fragment_b, container, false);}
}

(3)、创建Activity布局

接下来,我们将创建Activity的布局文件,其中包含一个容器用于显示Fragment,以及四个按钮用于控制Fragment的添加、替换和移除操作。

activity_main.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"><FrameLayoutandroid:id="@+id/fragment_container"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid:id="@+id/btn_add_fragment_a"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Add Fragment A" /><Buttonandroid:id="@+id/btn_replace_fragment_b"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Replace with Fragment B" /><Buttonandroid:id="@+id/btn_remove_fragment"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Remove Fragment" /><Buttonandroid:id="@+id/btn_attach_fragment"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Attach Fragment" /></LinearLayout></LinearLayout>

在上面的布局文件中,我们使用<FrameLayout>作为容器来显示Fragment。下面的<LinearLayout>中包含四个按钮,分别用于添加FragmentA、替换为FragmentB、移除当前Fragment和附加Fragment。


(4)、 MainActivity

最后,我们将创建MainActivity并实现按钮的点击事件,用于动态添加和移除Fragment。

public class MainActivity extends AppCompatActivity {private FragmentManager fragmentManager;private FrameLayout fragmentContainer;private FragmentA fragmentA;private FragmentB fragmentB;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);fragmentManager = getSupportFragmentManager();fragmentContainer = findViewById(R.id.fragment_container);Button btnAddFragmentA = findViewById(R.id.btn_add_fragment_a);btnAddFragmentA.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {addFragment(new FragmentA());}});Button btnReplaceFragmentB = findViewById(R.id.btn_replace_fragment_b);btnReplaceFragmentB.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {replaceFragment(new FragmentB());}});Button btnRemoveFragment = findViewById(R.id.btn_remove_fragment);btnRemoveFragment.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {removeFragment();}});Button btnAttachFragment = findViewById(R.id.btn_attach_fragment);btnAttachFragment.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {attachFragment();}});// 初始化并添加 FragmentAfragmentA = new FragmentA();addFragment(fragmentA);}private void addFragment(Fragment fragment) {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.add(R.id.fragment_container, fragment);transaction.addToBackStack(null);transaction.commit();}private void replaceFragment(Fragment fragment) {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.replace(R.id.fragment_container, fragment);transaction.addToBackStack(null);transaction.commit();}private void removeFragment() {Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container);if (fragment != null) {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.remove(fragment);transaction.commit();}}private void attachFragment() {if (fragmentB == null) {fragmentB = new FragmentB();FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.add(R.id.fragment_container, fragmentB);transaction.detach(fragmentB);transaction.commit();} else {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.attach(fragmentB);transaction.commit();}}
}

MainActivity中,我们首先获取FragmentManager和容器FrameLayout的实例。然后,我们为三个按钮设置点击事件监听器。

  • "Add Fragment A"按钮会调用addFragment()方法,将FragmentA实例动态添加到容器中。
  • "Add Fragment B"按钮会调用addFragment()方法,将FragmentB实例动态添加到容器中。
  • "Remove Fragment"按钮会调用removeFragment()方法,移除当前容器中的Fragment。

addFragment()方法中,我们使用FragmentTransaction来添加Fragment。我们还调用了addToBackStack()方法,这样当用户按下返回键时,Fragment就会从容器中移除。

removeFragment()方法中,我们首先使用findFragmentById()方法获取当前容器中的Fragment实例。如果存在Fragment,我们就使用FragmentTransaction将其从容器中移除。


当你运行这个应用程序时,你会看到一个空白的容器和三个按钮。点击"Add Fragment A"或"Add Fragment B"按钮,相应的Fragment就会动态添加到容器中。点击"Remove Fragment"按钮,当前容器中的Fragment就会被移除。你还可以反复添加和移除Fragment,观察其行为。


3、使用 FragmentManager 管理 Fragment

FragmentManager 提供了一系列方法用于管理 Fragment 的生命周期和事务。我们可以使用它来添加、移除、替换和附加 Fragment。


public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获取 FragmentManagerFragmentManager fragmentManager = getSupportFragmentManager();// 开启一个事务FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();// 替换 FragmentFragment fragmentA = new FragmentA();fragmentTransaction.replace(R.id.fragment_container, fragmentA);// 提交事务fragmentTransaction.commit();}
}

MainActivity中,我们首先获取FragmentManager和容器FrameLayout的实例,并初始化fragmentAfragmentB实例。


然后,我们为四个按钮设置点击事件监听器:

  • "Add Fragment A"按钮会调用addFragment()方法,将FragmentA实例添加到容器中。

  • "Replace with Fragment B"按钮会调用replaceFragment()方法,用FragmentB实例替换当前容器中的Fragment。

  • "Remove Fragment"按钮会调用removeFragment()方法,移除当前容器中的Fragment。

  • "Attach Fragment"按钮会调用attachFragment()方法,首次点击时会添加并分离FragmentB实例,之后点击则会重新附加该Fragment实例。


让我们逐一了解这些方法的实现:

首先,addFragment()方法

private void addFragment(Fragment fragment) {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.add(R.id.fragment_container, fragment);transaction.addToBackStack(null);transaction.commit();
}

这个方法使用FragmentTransaction来添加一个新的Fragment实例到容器中。我们调用add()方法来添加Fragment,并使用addToBackStack()方法将该事务添加到回退栈中,以便用户可以通过返回键来撤销该操作。


其次,replaceFragment()方法:

private void replaceFragment(Fragment fragment) {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.replace(R.id.fragment_container, fragment);transaction.addToBackStack(null);transaction.commit();
}

这个方法使用FragmentTransaction将当前容器中的Fragment替换为一个新的Fragment实例。我们调用replace()方法来替换Fragment,并同样使用addToBackStack()方法将该事务添加到回退栈中。


然后,removeFragment()方法:

private void removeFragment() {Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container);if (fragment != null) {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.remove(fragment);transaction.commit();}
}

这个方法首先使用findFragmentById()方法获取当前容器中的Fragment实例。如果存在Fragment,我们就使用FragmentTransaction将其从容器中移除。


最后,attachFragment()方法:

private void attachFragment() {if (fragmentB == null) {fragmentB = new FragmentB();FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.add(R.id.fragment_container, fragmentB);transaction.detach(fragmentB);transaction.commit();} else {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.attach(fragmentB);transaction.commit();}
}

这个方法用于演示detach()attach()方法的使用。首次点击"Attach Fragment"按钮时,我们会添加一个新的FragmentB实例,然后立即将其分离。之后再次点击该按钮时,我们会重新附加该Fragment实例。这种做法可以在不销毁Fragment的情况下临时隐藏它,从而保留其状态。


在上面的代码中,我们还在onCreate()方法中初始化并添加了FragmentA实例。

当你运行这个应用程序时,你会看到一个显示FragmentA的容器和四个按钮。你可以尝试点击不同的按钮,观察Fragment的添加、替换、移除和附加/分离操作。

通过这个案例,能够更好地理解如何使用FragmentManager来管理Fragment的生命周期和事务。FragmentManager提供了丰富的方法,如add()replace()remove()attach()detach()等,让你可以灵活地控制Fragment的行为。你还可以使用addToBackStack()方法将Fragment事务添加到回退栈中,从而实现类似Activity的导航行为。


结语:

通过本文的深入解析,你应该对Fragment有了更全面的理解。无论是在构建新的应用还是优化现有项目,Fragment都是你不可或缺的工具。Fragment的潜力远不止于此。

在下一篇文章中,我们将探索如何使用Fragment实现更高级的界面切换效果,以及如何在Fragment之间传递数据。敬请期待!


http://www.lryc.cn/news/345220.html

相关文章:

  • 深度解读DreamFusion:一站式AI解决方案
  • JVM-02
  • 【一起深度学习——NIN】
  • 数字工厂管理系统如何助力企业数据采集与分析
  • uniap之微信公众号支付
  • Django知识点总结
  • 算法(C++
  • Python专题:六、循环语句(1)
  • 力扣2105---给植物浇水II(Java、模拟、双指针)
  • Windows设置Redis为开机自启动
  • 行业早报5.10
  • Java+SpringBoot+JSP实现在线心理评测与咨询系统
  • 机器学习算法应用——K近邻分类器(KNN)
  • python数据分析——数据的选择和运算
  • 《CKA/CKAD应试指南/从docker到kubernetes 完全攻略》学习笔记 第8章 deployment
  • 步态识别论文(6)GaitDAN: Cross-view Gait Recognition via Adversarial Domain Adaptation
  • K8S中的弹性云服务如何搭建,可能遇到的问题,如何解决!(稳啦!!!!全都稳啦!!!)
  • 新增分类——后端
  • 20232801 2023-2024-2 《网络攻防实践》实践九报告
  • 类和对象--this引用原理
  • 力扣:416. 分割等和子集(Java,动态规划:01背包问题)
  • Vue进阶之Vue项目实战(一)
  • 预告 | 飞凌嵌入式邀您共聚2024上海充换电展
  • vite 打包配置并部署到 nginx
  • ResponseHttp
  • 【题解】非对称之美(规律)
  • 遇到如此反复的外贸客户,你可以这样做~
  • 【数据库】简单SQL语句
  • K邻算法:在风险传导中的创新应用与实践价值
  • 【小白的大模型之路】基础篇:Transformer细节