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

相关推荐
C4rpeDime2 小时前
自建MD5解密平台-续
android
鲤籽鲲3 小时前
C# Random 随机数 全面解析
android·java·c#
m0_548514777 小时前
2024.12.10——攻防世界Web_php_include
android·前端·php
凤邪摩羯8 小时前
Android-性能优化-03-启动优化-启动耗时
android
凤邪摩羯8 小时前
Android-性能优化-02-内存优化-LeakCanary原理解析
android
喀什酱豆腐8 小时前
Handle
android
m0_7482329210 小时前
Android Https和WebView
android·网络协议·https
m0_7482517210 小时前
Android webview 打开本地H5项目(Cocos游戏以及Unity游戏)
android·游戏·unity
m0_7482546612 小时前
go官方日志库带色彩格式化
android·开发语言·golang
zhangphil12 小时前
Android使用PorterDuffXfermode模式PorterDuff.Mode.SRC_OUT橡皮擦实现“刮刮乐”效果,Kotlin(2)
android·kotlin