Android Fragment:详解,结合真实开发场景Navigation

目录

1)Fragment是什么

2)Fragment的应用场景

3)为什么使用Fragment?

4)Fragment如何使用

5)Fragment的生命周期

6)Android开发,建议是多个activity,还是activity结合fragment,优缺点如何?

7)Fragment和Activity的通讯、返回键如何处理

8)Navigation搭配Fragment使用后,事务是怎么样?

一、Fragment是什么


Fragment是Android中的一种组件,直译为"碎片"或"片段",可以看作是Activity的模块化部分。

它主要用于承载一部分用户界面和逻辑,并可以在多个Activity中复用。Fragment具有自己的生命周期,能接收输入事件,可以在Activity运行时被添加、移除、替换或隐藏。此外,Fragment还允许开发者通过FragmentManager来管理其生命周期和事务,如添加、删除、替换Fragment等。

二、Fragment的应用场景


导航

  1. UI一:
  2. UI二:

三、为什么使用Fragment?


  1. 通过将复杂的界面拆分成多个Fragment,每个Fragment负责一部分UI和逻辑,可以提高代码的复用性和可维护性。不同的Fragment可以专注于处理特定的UI或逻辑,使得代码更加清晰和易于管理。
  2. Fragment可以被多个Activity复用,提高了代码的复用率。在模块化开发中,一个Fragment可以代表一个独立的业务模块,从而在不同的地方重复使用。

四、Fragment如何使用


4.1 Fragment一般搭配navigation进行使用


(1)创建一个导航条+容器:也就是我们上面案例种的左边部分(导航条)和内容显示部分(容器)

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/bnv_main_navigationbar"
        android:layout_width="300dp"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:paddingHorizontal="9dp"
        app:itemBackground="@color/white"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:menu="@menu/backstage_menu_setting" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/home_fragmentcontainerview"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@drawable/dingdian_pic_background_sys"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toEndOf="@+id/bnv_main_navigationbar"
        app:layout_constraintTop_toBottomOf="@+id/backstage_constraintlayout"
        app:navGraph="@navigation/backstage_nav" />
        
</androidx.constraintlayout.widget.ConstraintLayout>

(2)那么导航条view和容器view我们已经创建出来,那么导航条的这些:"首页","内容"这些item如何来呢?没错,可以看到上面我们使用了 app:menu="@menu/backstage_menu_setting" ,我们需要创建meun对象出来。

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/backstage_cottoncandyfragment"
        android:title="首页"/>
    <item
        android:id="@+id/backstage_paramsetfragment"
        android:title="内容"/>

    <item
        android:id="@+id/backstage_datastatfragment"
        android:title="咨讯"/>
    <item
        android:id="@+id/backstage_languagefragment"
        android:title="产品"/>
    <item
        android:id="@+id/backstage_errorstatfragment"
        android:title="图库"/>
    <item
        android:id="@+id/backstage_resetpwdfragment"
        android:title="消息"/>
    <item
        android:id="@+id/backstage_localalarmclockfragment"
        android:title="广告"/>
    <item
        android:id="@+id/backstage_permissionfragment"
        android:title="设置"/>
</menu>

(3)下面我们就需要创建fragment了,Fragment就是右边部分的容器内容。

kt 复制代码
@AndroidEntryPoint
class PriceFragment : BaseFragment<BackstageFragmentPriceBinding, ErrorStatFragmentVM>() {


    override val mViewModel: ErrorStatFragmentVM by viewModels()
    override fun createVB() = BackstageFragmentPriceBinding.inflate(layoutInflater)


    override fun BackstageFragmentPriceBinding.initView() {

    }

    override fun initObserve() {
    }

    override fun initRequestData() {
        mViewModel.getBanners()
        mViewModel.getArticleData()
    }

}
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/backstage_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Datastat"
        android:textSize="40dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

(4)那么如何设置点击这些"首页","资讯"就能打开对应的Fragment呢?使用Navigation,让我们可以使用非常简短的代码就能实现跳转。首先我们要创建一个导航文件

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/backstage_nav"
    app:startDestination="@id/backstage_datastatfragment">

    <fragment
        android:id="@+id/backstage_cottoncandyfragment"
        android:name="com.quyunshuo.wanandroid.home.ui.fragment.CottonCandyFragment"
        android:label="CottonCandyFragment" />

    <fragment
        android:id="@+id/backstage_paramsetfragment"
        android:name="com.quyunshuo.wanandroid.home.ui.fragment.ParamSetFragment"
        android:label="ParamSetFragment" />

    <fragment
        android:id="@+id/backstage_datastatfragment"
        android:name="com.quyunshuo.wanandroid.home.ui.fragment.DataStatFragment"
        android:label="DataStatFragment" />

    <fragment
        android:id="@+id/backstage_errorstatfragment"
        android:name="com.quyunshuo.wanandroid.home.ui.fragment.ErrorStatFragment"
        android:label="ErrorStatFragment" />

    <fragment
        android:id="@+id/backstage_languagefragment"
        android:name="com.quyunshuo.wanandroid.home.ui.fragment.LanguageFragment"
        android:label="LanguageFragment" />
    <fragment
        android:id="@+id/backstage_resetpwdfragment"
        android:name="com.quyunshuo.wanandroid.home.ui.fragment.ResetPwdFragment"
        android:label="ResetPwdFragment" />

    <fragment
        android:id="@+id/backstage_localalarmclockfragment"
        android:name="com.quyunshuo.wanandroid.home.ui.fragment.LocalAlarmClockFragment"
        android:label="LocalAlarmClockFragment" />

    <fragment
        android:id="@+id/backstage_permissionfragment"
        android:name="com.quyunshuo.wanandroid.home.ui.fragment.PermissionFragment"
        android:label="PermissionFragment" />

    <fragment
        android:id="@+id/backstage_otherfragment"
        android:name="com.quyunshuo.wanandroid.home.ui.fragment.OtherFragment"
        android:label="OtherFragment" />
</navigation>

注意,android:id="@+id/backstage_otherfragment"的id必须和menu的item id必须相同,这样才能找到对应的fragment

(5)实现使用navcontroller实现跳转

kt 复制代码
  bnvMainNavigationbar.setNavigationItemSelectedListener{
            val findNavController = findNavController(homeFragmentcontainerview.id)
            findNavController.navigate(it.itemId)
            true

        }

五、Fragment的生命周期


想要了解Fragment的生命周期,离不开Activity的生命周期,所以我们会一起讲到。

Fragment的生命周期由FragmentManager管理,FragmentManager负责将Fragment添加到Activity中,并在Fragment不再需要时将其移除。在Fragment的生命周期中,有几个关键点需要注意:

1)当Fragment被添加到Activity中时,会依次调用onAttach()、onCreate()、onCreateView()、onActivityCreated()、onStart()和onResume()方法。

2)当Fragment对用户不可见时(如被另一个Activity覆盖),会依次调用onPause()、onStop()方法。

3)当Fragment被移除或宿主Activity被销毁时,会依次调用onPause()、onStop()、onDestroyView()、onDestroy()和onDetach()方法。注意,如果只是Fragment被切换了,不会调用onDestroy()方法,只是调用onDestroyView,不要以为他离开了界面就是销毁了

5.1 Fragment的生命周期通过一系列回调方法来管理,这些方法在Fragment状态变化时被调用。以下是Fragment的主要生命周期回调方法:


1)onAttach(Context context):当Fragment与Activity关联时调用。这是Fragment生命周期中的第一个回调方法,此时可以获取到宿主Activity的引用。

2)onCreate(Bundle savedInstanceState):当Fragment被创建时调用。用于初始化Fragment的基本数据,如加载布局文件等。

3)onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState):创建Fragment的视图层次结构。如果Fragment没有UI,可以返回null。

4)onViewCreated(View view, Bundle savedInstanceState):当Fragment的视图被创建时调用。此时可以对视图进行进一步的初始化操作。

5)onActivityCreated(Bundle savedInstanceState):当宿主Activity的onCreate()方法完成后调用。此时Fragment的视图层次结构已完全创建,可以安全地与Activity的视图进行交互。

6)onStart():Fragment对用户可见时调用。此时Fragment开始对用户可见,但可能还未完全交互。

7)onResume():Fragment开始与用户交互时调用。此时Fragment完全可见且可交互。

8)onPause():Fragment失去焦点或停止与用户交互时调用。此时应保存一些重要数据或停止一些操作,如动画、网络请求等。

9)onStop():Fragment完全不可见时调用。此时应释放一些资源或做一些清理工作。

10)onDestroyView():Fragment的视图被销毁时调用。此时应释放与视图相关的资源。

11)onDestroy():Fragment被销毁时调用。此时应释放Fragment的成员变量和数据,以便回收内存和资源。

12)onDetach():Fragment与Activity分离时调用。此时应做一些最终的清理工作。

onDestroy和onDestroyView方法的区别

一、onDestroyView():

1)当Fragment的视图层次结构(即UI)被销毁时调用。这通常发生在Fragment不再需要显示其UI时,可能是因为用户离开了包含该Fragment的Activity,或者因为Fragment被替换或移除了。

2)在onDestroyView()被调用后,Fragment仍然存在于内存中,并且其状态(如成员变量等)仍然保持。但是,与视图相关的资源应该被释放,以避免内存泄漏。

二、onDestroy():

1)当Fragment被销毁时调用。这是Fragment生命周期中的最后一个回调方法,表示Fragment即将被系统回收,其资源将被完全释放。

2)在onDestroy()被调用后,Fragment无法再接收到任何生命周期回调,并且其资源(如内存)将被系统回收。

onDestroyView()主要负责释放与视图相关的资源,而onDestroy()则负责清理Fragment占用的所有资源。

六、Android开发,建议是多个activity,还是activity结合fragment,原因是什么


主要取决于你的应用需求、设计目标以及用户体验的考虑。下面是一些关于这两种方式的优缺点以及选择建议:
1. 使用多个Activity

优点:

kt 复制代码
清晰的逻辑分离:每个Activity可以专注于一个特定的任务或用户流程,使得代码更加模块化和易于管理。
任务栈管理:Android系统通过任务栈管理Activity,可以很方便地实现页面之间的跳转和返回,尤其是在处理复杂的用户流程时。
内存管理:当Activity不再需要时,系统可以更容易地回收其占用的资源。

缺点:

kt 复制代码
    界面切换动画:Activity之间的切换可能会比Fragment之间的切换更重,因为涉及到整个界面的重建。
    数据共享:Activity之间的数据共享可能需要通过Intent、全局变量或数据库等方式,相对复杂。
    用户体验:在某些情况下,过多的Activity跳转可能会导致用户感到困惑,尤其是在需要频繁切换界面时。

2.使用Activity结合Fragment

优点:

kt 复制代码
 灵活的界面布局:Fragment可以在一个Activity中重用,并且可以在运行时动态地添加、移除或替换,非常适合实现复杂的用户界面布局。
    更好的用户体验:Fragment之间的切换通常比Activity之间的切换更流畅,因为不需要重建整个界面。
    数据共享:Fragment与宿主Activity之间的数据共享更加直接和方便,可以通过接口回调等方式实现。

缺点:
```kt
    复杂性增加:Fragment的生命周期比Activity更复杂,需要更仔细地管理,以避免内存泄漏等问题。
    状态管理:Fragment的状态管理可能更加复杂,尤其是在处理多个Fragment的嵌套和动态变化时。

选择建议

kt 复制代码
    如果你的应用界面相对简单,且每个界面之间的逻辑相对独立,可以考虑使用多个Activity。
    如果你的应用需要实现复杂的用户界面布局,或者需要在同一个Activity中动态地展示不同的内容区域,那么使用Activity结合Fragment可能是一个更好的选择。
    考虑用户体验和内存管理。Fragment之间的切换通常更流畅,但也需要更仔细地管理其生命周期和状态。
    考虑应用的维护性和可扩展性。使用Fragment可以使代码更加模块化和可重用,但也可能增加复杂性。

七、返回键如何处理

在activity中,我们导航了很多的Fragment,比如从A Framgent到了B Fragment,再到了C Fragment,如果我想点击物理的返回按键,如何返回到到一个Fragment呢?并且,如果到了最初的A Framgnet,想提示如果再次点击将退出app这种的提示应该如何写呢?

kt 复制代码
 override fun onBackPressed() {
        val navController =findNavController(mBinding.homeFragmentcontainerview.id)
        val fragmentPopped = navController.popBackStack()
        Log.d("fragmentPopped", "onBackPressed: "+fragmentPopped)

        // 如果popBackStack()返回false,意味着没有Fragment可以返回了
        // 这里你可以假设已经回到了最开始的Fragment,或者根本就没有Fragment在栈中
        if (!fragmentPopped) {
            // 没有任何Fragment可以返回了,结束Activity
            // 获取当前时间戳
            val currentTime = System.currentTimeMillis()

            // 判断与上一次点击返回键的时间间隔是否小于1秒
            if (currentTime - backPressedTime < 1000) {
                super.onBackPressed() // 执行默认的返回键操作(退出Activity)
            } else {
                Toast.makeText(this, "再次点击返回键退出", Toast.LENGTH_SHORT).show()
                backPressedTime = currentTime // 更新上一次点击返回键的时间戳
            }
        }
    }

navController.popBackStack()会移除栈顶的Fragment,如果存在fragment,就会返回true,否则返回false。

7.1 假如说,我想从A Fragment跳到B Fragment的时候,我想A Fragment直接就销毁了呢?

xml 复制代码
  <fragment
        android:id="@+id/home_homefragment"
        android:name="com.quyunshuo.wanandroid.home.ui.fragment.HomeFragment"
        android:label="HomeFragment" >
        <action
            android:id="@+id/home_action_home_homefragment_to_home_makefragment"
            app:destination="@id/home_makefragment"
            app:popUpTo="@id/home_homefragment"
            app:popUpToInclusive="true"/>
            <fragment/>

app:popUpTo="@id/home_homefragment"

app:popUpToInclusive="true"

的意思就是跳转的时候,将之前的Fragment销毁掉。就保留自己作为栈顶

八、Navigation搭配Fragment使用后,事务是怎么样?

当使用Navigation组件来管理Fragment的创建和切换时,Fragment的事务(Transaction)是通过Navigation图(Navigation Graph)和NavController来隐式处理的。这种方式简化了Fragment的切换逻辑,让开发者可以更专注于Fragment之间的交互和业务逻辑的实现。

Fragment事务的隐式处理

1)在传统的Fragment管理中,你可能需要显式地调用FragmentManager的beginTransaction()、add()、replace()等方法来创建Fragment事务。但在使用Navigation组件时,这些操作都被封装在Navigation图内,并由NavController根据导航操作(如点击按钮、接收通知等)来自动处理。

2)例如,当你在Navigation图中定义了两个Fragment(A和B),并从一个Fragment(A)到另一个(B)的导航时,你只需要在A Fragment中调用NavController的navigate()方法,并传入目标Fragment的ID或Action ID。NavController会根据Navigation图自动处理Fragment的添加、替换和移除等事务。

https://blog.csdn.net/weixin_36049771/article/details/117580874?ops_request_misc=\&request_id=\&biz_id=102\&utm_term=Fragment的任务栈\&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb\~default-3-117580874.142^v100^pc_search_result_base4\&spm=1018.2226.3001.4187

相关推荐
ZHANG13HAO2 小时前
调用脚本实现 App 自动升级(无需无感、允许进程中断)
android
圆号本昊3 小时前
【2025最新】Flutter 加载显示 Live2D 角色,实战与踩坑全链路分享
android·flutter
小曹要微笑3 小时前
MySQL的TRIM函数
android·数据库·mysql
mrsyf4 小时前
Android Studio Otter 2(2025.2.2版本)安装和Gradle配置
android·ide·android studio
DB虚空行者4 小时前
MySQL恢复之Binlog格式详解
android·数据库·mysql
liang_jy6 小时前
Android 事件分发机制(一)—— 全流程源码解析
android·面试·源码
峥嵘life7 小时前
2026 Android EDLA 认证相关资源网址汇总(持续更新)
android·java·学习
kkk_皮蛋7 小时前
在移动端使用 WebRTC (Android/iOS)
android·ios·webrtc
aqi008 小时前
FFmpeg开发笔记(九十六)采用Kotlin+Compose的视频编辑器OpenVideoEditor
android·ffmpeg·kotlin·音视频·流媒体
诸神黄昏EX9 小时前
Android Safety 系列专题【篇一:系统签名】
android