Android 12 源码分析 —— 应用层 四(SystemUI的基本布局设计及其基本概念)

Android 12 源码分析 —— 应用层 四(SystemUI的基本布局设计及其基本概念)

在上两篇文章中,我们介绍SystemUI的启动过程,以及基本的组件依赖关系。基本的依赖关系请读者一定要掌握,因为后面的文章,将会时常出现这些依赖关系的使用,届时将会一笔带过,而不会详细说明他们的实现细节和原理。

接下来我们将介绍,SystemUI中各个UI部分是如何被加入屏幕中的,以及查看下拉状态中的各个图标的实现。

但是在进入真正的主题之前,我们还需要了解SystemUI中的各个UI的基本布局以及名字,只有了解了这些基本布局和名字,才能够在许多相似名字中分清楚具体的对象是谁。

接下来我们将介绍SystemUI的基本布局设计,看看整个SystemUI的布局被大致分成了哪些内容,以及这些内容对应的业务是什么。

SystemUI的window划分

在“Android 12 源码分析 —— 应用层 二(SystemUI大体组织和启动过程)http://t.csdn.cn/chk6Y”文章中,我们提及过,SystemUI可以通过WindowManager来显示自己的UI。

事实上,SystemUI正是通过WindowManager来添加自己的主要的UI视图。在SystemUI中,将以下几个部分,分别放置在不同的Window中,然后通过WindowManager将其添加到屏幕上。

  1. StatusBar——状态栏
  2. NotificationShade——通知卷帘(我们常说的下拉状态栏)
  3. NavigationBar——导航栏

注意:除了上面三个常见的window以外,还有其他的window,如GlobalActionDialog(负责显示——关机,重启的弹框),VolumeDialog(显示音量调节),这些window将会在我们介绍各个子主题的时候,依次登场

可能会有读者疑惑:锁屏呢?不在一个单独window下面吗?事实上,锁屏不在一个单独的window中,其本身就是NotificationShade(通知卷帘,即下拉状态栏)。换句话说,锁屏的内容和下拉状态栏的内容在同一个window中。

这里一定要注意的一点是:对应的中文命名方式,从此刻开始,将在对应的类后面用小括号标记其中文命名,之所以有这样的标记,是因为英文名字有很多相似之处,可能不利于记忆,如:StatusBar虽然叫做状态栏,但是在不同的Window中有不同的StatusBar(状态栏),比如,在锁屏状态下有KeyguardViewStatusBar(锁屏状态栏);同样地,在NotificationShade(通知卷帘,即下拉状态栏)中本应该显示StatusBar(状态栏)的地方,并不叫StatusBar。而为了便于记忆,将其中文名字放在小括号中

为了便于理解,现在window标记出来,如下:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

有了上面的直观感受,我们将结合SystemUI的layout文件,大体的介绍其UI布局及其相关概念,有了这些概念,才能够在纷繁复杂的源码中,找到对应的实现实体。

SystemUI的命名规则和设计模式

本文主题是SystemUI的布局介绍,但依然可能会存在这样的疑问:这些布局是什么时候被加载的?他们的加载流程是怎样的?

在后面的文章中,我们会依次介绍这些布局的加载,以及怎么处理各种事件,但再此之前,需要明白他们之间的设计模式和命名规则。

SystemUI各个小模块采用:MVC,MVP等设计模式,因此在他们的命名体系中,经常以xxxView,xxxController,xxxPresenter来代表。例如,代表StatusBar(状态栏)的StatusBarWindowView(状态栏窗口视图),StatusBarWindowController(状态栏窗口控制器),而与StatusBarWindow相关的model即为StatusBar(状态栏)

当然,SystemUI编辑历史长,中间有几次大的修改,并不是所有的类,都遵循这些规则,不过读者在阅读源码的时候,可以按照这些思路进行思考。

而本文以介绍SystemUI布局为主题,而不关心这些布局的加载时刻和流程,但我们会用一段小提示来,简略的概括这些布局的加载流程。在阅读这些简略加载流程的时候,会出现很多相似的名字,因此可以按照上面的命名规则来对应相应的实体

读者可以忽略这些加载流程,因为在后续的文章中,将会详细的介绍这些UI的加载流程和用户操作

我们先从最复杂的NotificationShade(通知卷帘,下拉状态栏)介绍起。

SystemUI的NotificationShade(通知卷帘,即下拉状态栏)window的详细布局

NotificationShade(通知卷帘,即下拉状态栏)window的的加载流程

按照上文的说明,会先简略介绍,这个布局的加载流程,如下:

  1. SytemUIService启动之后,调用SystemUIApplication的startServicesIfNeeded()启动相应的服务(“Android 12 源码分析 —— 应用层 二(SystemUI大体组织和启动过程)http://t.csdn.cn/chk6Y”)
  2. 启动的服务中,有一个叫做StatusBar,它会在第一步中,被调用start()方法
  3. 在start()方法中,会调用createAndAddWindows()方法
  4. createAndAddWindows()方法会调用makeStatusBarView()方法
  5. makeStatusBarView()方法会调用inflateStatusBarWindow()方法
  6. inflateStatusBarWindow()方法会调用SuperStatusBarViewFactory的getNotificationShadeWindowView()方法
  7. getNotificationShadeWindowView()方法会去加载并解析R.layout.super_notification_shade,也即super_notification_shade.xml
  8. 第7步完成之后,会回到第4步中,并调用NotificationShadeWindowController的attach()方法,将对应的UI,添加到屏幕上

注意:对于上面的调用过程,读者可以完全不用在意,因为后面的文章,将会详细介绍

接下来分析,super_notification_shade.xml

NotificationShade(通知卷帘,即下拉状态栏)window的顶层视图

super_notification_shade.xml的源文件如下:

注意:为了减轻阅读障碍,我会省略掉一些非常常见的代码,如一些属性的定义和赋值,省略一些非常简单的布局视图

<com.android.systemui.statusbar.phone.NotificationShadeWindowView>

    <com.android.systemui.statusbar.BackDropView>
        
    </com.android.systemui.statusbar.BackDropView>

    <com.android.systemui.scrim.ScrimView
        android:id="@+id/scrim_behind" />

    <com.android.systemui.scrim.ScrimView
        android:id="@+id/scrim_notifications"/>

    <com.android.systemui.statusbar.LightRevealScrim
            android:id="@+id/light_reveal_scrim" />

    <include layout="@layout/status_bar_expanded"/>

    <include layout="@layout/brightness_mirror_container" />

    <com.android.systemui.scrim.ScrimView
        android:id="@+id/scrim_in_front" />

    <!-- Keyguard messages -->
    <FrameLayout>
        <com.android.keyguard.KeyguardMessageArea
            android:id="@+id/keyguard_message_area"/>
    </FrameLayout>

    <com.android.systemui.biometrics.AuthRippleView/>
</com.android.systemui.statusbar.phone.NotificationShadeWindowView>

从上面的代码结构看,非常滴简单,我们依次介绍如下:

  1. NotificationShadeWindowView:通知卷帘窗口,即下拉状态栏窗口的最顶层视图

  2. BackDropView:幕布视图,它会显示最最底部的一些背景,如播放音乐的时候,显示音乐的专辑图片

  3. ScrimView:总共有三个,他们主要负责遮罩,如在锁屏状态下,整个锁屏界面,稍微变暗淡一些,即通过设置遮罩的透明度来实现

  4. LightRevealScrim:也是遮罩相关的视图,它负责处理一些渐变的动画,如在设置中打开息屏显示,那么在点击电源按钮的时候,将会显示对应的动画,如下图
    在这里插入图片描述

  5. status_bar_expanded.xml:即展开的状态中的布局,这里面详细列出了下拉状态栏之后,应该显示哪些内容

  6. brightness_mirror_container.xml:这个是调节亮度条对应的镜像视图,因为还有一个亮度调节条他在status_bar_expanded中,之所以有这个,是为了在调节亮度的时候,隐藏status_bar_expanded中的内容

  7. KeyguardMessageArea:锁屏信息显示区域,如输入pin错误,则会在此处显示wrong pin

除了第七点,可以直接给出参考图以外,其他的都无法给出特别好的参考图,因此可以使用文末推荐的布局查看工具,进行查看

在上面中出现了两个include的xml文件,如果每个文件都介绍,将会消耗大量的篇幅,同时又有些详略不得当,因此,针对一些简单的layout文件,将会一笔带过,如上面的brightness_mirror_container.xml文件。而这些略过的文件,在某些子主题下,将会详细介绍,如上面的brightness_mirror_container.xml将会在调节音量的文章中,详细介绍

因此接下来将会介绍status_bar_expanded.xml文件

status_bar_expanded.xml文件分析

status_bar_expanded.xml文件原文如下:

注意:这里依然会省略掉一些属性定义和赋值

<com.android.systemui.statusbar.phone.NotificationPanelView
    android:id="@+id/notification_panel">
    <FrameLayout
        android:id="@+id/big_clock_container" />

    <ViewStub
        android:id="@+id/keyguard_qs_user_switch_stub"/>

    <include
        layout="@layout/keyguard_bottom_area"
        android:visibility="gone" />

    <ViewStub
        android:id="@+id/keyguard_user_switcher_stub" />

    <include layout="@layout/status_bar_expanded_plugin_frame"/>

    <include layout="@layout/dock_info_bottom_area_overlay" />

    <com.android.keyguard.LockIconView
        android:id="@+id/lock_icon_view">
    </com.android.keyguard.LockIconView>

    <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
        android:id="@+id/notification_container_parent">

        <include layout="@layout/keyguard_status_view"/>

        <include layout="@layout/dock_info_overlay" />

        <FrameLayout android:id="@+id/qs_frame"/>

        <androidx.constraintlayout.widget.Guideline 
            android:id="@+id/qs_edge_guideline"/>

        <com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
            android:id="@+id/notification_stack_scroller"/>

        <include layout="@layout/ambient_indication"
            android:id="@+id/ambient_indication_container" />

        <include layout="@layout/photo_preview_overlay" />

        <include
            layout="@layout/keyguard_status_bar"
            android:visibility="invisible" />

        <Button
            android:id="@+id/report_rejected_touch"/>
        <com.android.systemui.statusbar.phone.TapAgainView
            android:id="@+id/shade_falsing_tap_again"/>
    </com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>

    <FrameLayout
        android:id="@+id/preview_container">
    </FrameLayout>
</com.android.systemui.statusbar.phone.NotificationPanelView>

对上面文件的介绍如下:

  1. NotificationPanelView:整个通知栏和快速设置图标的顶层目录
  2. id为big_clock_container的FrameLayout:显示一个较大的时钟视图
  3. 两个ViewStub:这个跟多用户的切换视图有关,当点击多用户的时候,会在这两个ViewStub之一中,显示切换的视图
  4. keyguard_bottom_area.xml:显示锁屏底部区域,如充电中…
  5. status_bar_expanded_plugin_frame.xml:跟SystemUI的插件有关,现在读者可以不用管,后面会详细介绍其细节
  6. dock_info_bottom_area_overlay.xml:空的
  7. LockIconView:锁屏界面下的锁图标
  8. NotificationsQuickSettingsContainer:通知和快速设置的容器,其中显示通知和快速设置
  • keyguard_status_view.xml:显示锁屏相关的状态视图,如显示日期
  • dock_info_overlay.xml: 空的
  • id为qs_frame的FrameLayout:用于快速设置的父容器
  • Guideline:用于调整布局的视图
  • NotificationStackScrollLayout:用于显示通知的父容器
  • ambient_indication.xml:空的
  • photo_preview_overlay.xml:空的
  • keyguard_status_bar.xml:锁屏状态下的,状态栏
  • Button:调试使用,不用管
  • TapAgainView:显示,再按一次的视图,现在已经不用了
  1. id为preview_container的FrameLayout:预览图片显示视图,如滑动相机图片,会先显示一个相机的图片

注意:对于上面某些xml文件的说明为:空的,一方面,部分内容已经不再使用,另一方面,部分内容将会在后续文章中出现。

在上面的xml文件中,细心的读者可能已经注意到,即锁屏也是在NotificationShade窗口中的。为了能够直观的观察上面的内容,我们使用图片进行说明,如下图:
在这里插入图片描述

在上面的源码中,出现了

  1. keyguard_bottom_area.xml
  2. status_bar_expanded_plugin_frame.xml
  3. dock_info_bottom_area_overlay.xml
  4. keyguard_status_view.xml
  5. dock_info_overlay.xml
  6. ambient_indication.xml
  7. photo_preview_overlay.xml
  8. keyguard_status_bar.xml
    在上面文件,其中status_bar_expanded_plugin_frame.xml,dock_info_bottom_area_overlay.xml,dock_info_overlay.xml,ambient_indication.xml,photo_preview_overlay.xml一部分没有被使用,一部分将会在后面的子主题中介绍,现在略过并不影响阅读和理解

剩下的keyguard_bottom_area.xml,keyguard_status_view.xml和keyguard_status_bar.xml三个文件,简单明了,能够非常容易的将UI对应上,因此不在此处介绍。这并不影响本文的阅读和理解。不过不用担心,在后续的文章中,我们还会介绍这三个文件,看看他们的交互和初始化过程,此处为了整体行文的紧凑,将其略去

虽然我们已经能够将锁屏相关的UI和代码建立一个联系,但是我们现在还不能将下拉设置中的UI和代码建立联系。接下来,我们处理这部分内容。

QuickSettings(快速设置)的布局分析

在上面的代码中,已经介绍了id为qs_frame的FrameLayout将用来显示快速设置,接下来看看他们是如何布局的。

注意:NotificationStackScrollLayout的布局细节将会在后文中详解

QuickSettings的加载流程

在上文我们知道,id为qs_frame的FrameLayout并没有使用include来加载一个layout,因为我们需要先简单说明一下,其加载过程,然后在看其布局结构

  1. SytemUIService启动之后,调用SystemUIApplication的startServicesIfNeeded()启动相应的服务(“Android 12 源码分析 —— 应用层 二(SystemUI大体组织和启动过程)http://t.csdn.cn/chk6Y”)
  2. 启动的服务中,有一个叫做StatusBar,它会在第一步中,被调用start()方法
  3. 在start()方法中,会调用createAndAddWindows()方法
  4. createAndAddWindows()方法会调用makeStatusBarView()方法
  5. makeStatusBarView()方法会找到id为qs_frame的FrameLayout并向其中添加一个QSFragment
  6. QSFragment会去加载qs_panel.xml文件,而这个文件,正是我们的快速设置的布局文件

qs_panel.xml文件分析

qs_panel.xml原文如下:

<com.android.systemui.qs.QSContainerImpl
    android:id="@+id/quick_settings_container" >

    <com.android.systemui.qs.NonInterceptingScrollView
        android:id="@+id/expanded_qs_scroll_view">
        <com.android.systemui.qs.QSPanel
            android:id="@+id/quick_settings_panel">
            <include layout="@layout/qs_footer_impl" />
        </com.android.systemui.qs.QSPanel>
    </com.android.systemui.qs.NonInterceptingScrollView>

    <include layout="@layout/quick_status_bar_expanded_header" />

    <include android:id="@+id/qs_detail" layout="@layout/qs_detail" />

    <include android:id="@+id/qs_customize" layout="@layout/qs_customize_panel"
        android:visibility="gone" />

</com.android.systemui.qs.QSContainerImpl>
  1. QSContainerImpl:快速设置的父容器
  2. NonInterceptingScrollView:快速设置中各个图标的ScrollView
  • QSPanel:QSPanel展示里面具体的详情
  • qs_footer_impl.xml:快速设置底部的显示视图,如编辑快速设置的图标,见后面图片的对应关系
  1. quick_status_bar_expanded_header.xml:快速设置中的头部区域,见下面的图片设置
  2. qs_detail.xml:快速设置的详细信息
  3. qs_customize.xml:编辑快速设置的界面

为了能够方便的对应起来,见下面的图片

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在上面的图片中我们可以看到,QSPanel内部,将会有有各种各样的快速设置的小图标,而这些图标被称为QSTile.

我们将会在QSPanel的源码分析中,详细讲解他们的加载过程。本文旨在介绍SystemUI的布局设计,而非对某个UI的具体细节。

介绍完了qs_frame的布局以后,我们还需要查看该window下面的最后一个布局NotificationStackScrollLayout

NotificationStackScrollLayout布局分析

NotificationStackScrollLayout是一个类,它也没有使用include来引用其他的布局文件,而其内部则是通过其他的方式来添加布局的。

NotificationStackScrollLayout加载通知布局的流程

  1. 当系统有通知到来时,调用NotificationListener的onNotificationPosted()方法
  2. 在onNotificationPosted方法中,会通知NotificationEntryManager的mNotifiListener的onNotificationPosted()方法
  3. 在该方法中,会调用addNotification()方法,然后在addNotification()中调用addNotificationInternal()方法
  4. 在addNotificationInternal()方法中,会调用NotificationRowBinderImpl的inflateViews()方法
  5. 在这个方法中,会去调用RowInFlaterTask的inflate()方法
  6. 在inflate()方法中,会去加载status_bar_notification_row.xml文件

接下来我们看看这个文件的内容

status_bar_notification_row.xml文件解析

status_bar_notification_row.xml文件的原文如下:

<com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
    android:id="@+id/expandableNotificationRow">
 <!--只有一个ExpandableNotificationRow-->
</com.android.systemui.statusbar.notification.row.ExpandableNotificationRow>

只有一项内容,当然其内部的内容,我们现在不需要关系,ExpandableNotificationRow是我们观察的最小布局,因为其内部已经涉及具体的内容该怎么显示了,现在我们只需要领略大概的布局,并明白相关的概念

  1. ExpandableNotificationRow:一个可展开的通知

在这里插入图片描述

注意:对于通知的排序,优先级等,我们将在后面的文章中,一一介绍,此处只需了解整体布局和基本概念即可

至此,NotificationShade窗口的布局介绍基本已经完成,在这里面我们熟悉了各个UI的实体,当然也省略了一些UI的实体,
省略的部分,将会在后面文章的子主题中,详细介绍。

接下来我们接续查看剩下的两个window——StatusBar和NavigationBar

StatusBar(状态栏)Window的详细布局

StatusBar(状态栏)window的加载流程

先简单介绍其加载流程

  1. SytemUIService启动之后,调用SystemUIApplication的startServicesIfNeeded()启动相应的服务(“Android 12 源码分析 —— 应用层 二(SystemUI大体组织和启动过程)http://t.csdn.cn/chk6Y”)
  2. 启动的服务中,有一个叫做StatusBar,它会在第一步中,被调用start()方法
  3. 在start()方法中,会调用createAndAddWindows()方法
  4. createAndAddWindows()方法会调用makeStatusBarView()方法
  5. makeStatusBarView()方法中,会调用inflateStatusBarWindow()方法
  6. 在inflateStatusBarWindow()方法中,会通过StatusBarComponent的getStatusBarWindowController()方法得到StatusBarWindowController
  7. 在StatusBarWindowController的构造函数中,会调用SuperStatusBarViewFactory的getStatusBarWindow()方法
  8. 而SuperStatusBarViewFactory的getStatusBarWindow()方法将会去加载super_status_bar.xml文件
  9. 在第四步的createAndAddWindows()方法中,会调用StatusBarWindowController的attach()方法,将其添加到屏幕上

接下来看看StatusBar(状态栏)的布局文件

StatusBar(状态栏)Window的顶层视图

super_status_bar.xml的源文件如下:

<com.android.systemui.statusbar.phone.StatusBarWindowView>
    <FrameLayout
        android:id="@+id/status_bar_launch_animation_container"/>
    <FrameLayout
        android:id="@+id/status_bar_container" />
</com.android.systemui.statusbar.phone.StatusBarWindowView>

非常,非常的清爽!!

  1. StatusBarWindow:表示了状态栏的最顶层视图
  2. id为status_bar_launch_animation_container的FrameLayout:在这里面显示动画,例如:从StatusBar(状态栏)中启动一个Activity时的动画显示区域
  3. id为status_bar_contianer的FrameLayout:这就是现实状态栏内容的主要区域

接下来我们查看其详细细节

StatusBar(状态栏)的布局分析

上面id为status_bar_contianer是一个FrameLayout,我们来看看其如何加载布局的。先简单介绍其布局加载流程

StatusBar(状态栏)布局加载流程

  1. SytemUIService启动之后,调用SystemUIApplication的startServicesIfNeeded()启动相应的服务(“Android 12 源码分析 —— 应用层 二(SystemUI大体组织和启动过程)http://t.csdn.cn/chk6Y”)
  2. 启动的服务中,有一个叫做StatusBar,它会在第一步中,被调用start()方法
  3. 在start()方法中,会调用createAndAddWindows()方法
  4. createAndAddWindows()方法会调用makeStatusBarView()方法
  5. makeStatusBarView()方法,会将CollapsedStatusBarFragment放入id为status_bar_container的FrameLayout中
  6. 而CollapsedStatusBarFragment会在其onCreateView的时候,加载并初始化status_bar.xml文件

status_bar.xml文件分析

status_bar.xml文件原文如下:

<com.android.systemui.statusbar.phone.PhoneStatusBarView
    android:id="@+id/status_bar">

    <ImageView
        android:id="@+id/notification_lights_out"/>

    <LinearLayout android:id="@+id/status_bar_contents">
        <FrameLayout>
            <include layout="@layout/heads_up_status_bar_layout" />

            <LinearLayout
                android:id="@+id/status_bar_left_side">
                <ViewStub
                    android:id="@+id/operator_name"/>

                <com.android.systemui.statusbar.policy.Clock
                    android:id="@+id/clock"/>

                <include layout="@layout/ongoing_call_chip" />

                <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
                    android:id="@+id/notification_icon_area"/>

            </LinearLayout>
        </FrameLayout>

        <!-- Space should cover the notch (if it exists) and let other views lay out around it -->
        <android.widget.Space
            android:id="@+id/cutout_space_view" />

        <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
            android:id="@+id/centered_icon_area"/>

        <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area">

            <include layout="@layout/system_icons" />
        </com.android.keyguard.AlphaOptimizedLinearLayout>
    </LinearLayout>

    <ViewStub
        android:id="@+id/emergency_cryptkeeper_text"/>

</com.android.systemui.statusbar.phone.PhoneStatusBarView>
  1. PhoneStatusBarView:状态栏内容的父容器
  2. 当状态栏被请求以SYSTEM_UI_FLAG_LOW_PROFILE模式显示时,这个视图负责显示一个小点
  3. id为status_bar_content的LinearLayout:显示状态栏内容
  • heads_up_status_bar_layout.xml:处在StatusBar中的部分提示信息
  • id为status_bar_left_side的LinearLayout:状态栏左边的显示区域
  • Space:填充中间的空白区域
  • AlphaOptimizedFrameLayout:中心图标显示区域
  • AlphaOptimizedLinearLayout:系统图标显示区域,如电量百分比
  1. id为emergency_cryptkeeper_text的ViewStub:显示只能拨打紧急呼救电话

从上面的布局文件可以看到,StatusBar(状态栏)大致分成了三个区域,左,中,右,现在只需要了解其中大体布局即可,即能够在阅读源码的时候,知道源码中的View指的是哪一部分区域即可。在后面的文章中,我们将详细介绍这些布局的内容和实现细节。

至此,我们了解了,SystemUI中,最重要的两个Window的布局。剩下最后一个Window即NavigationBar,因为其布局的简单,我们将在分析Android导航手势的时候,一并介绍

本文,只需要掌握如下几个概念即可,因为后面的系列文章,还会反复提及:

  1. SystemUI的Window的划分
  2. SystemUI的各个UI的名字如,NotificationShadeView,QS等等
  3. 知道对应的View的Controller的名字,大概会是什么样子,如NotificationShadeWindowView的Controller,应该叫做NotificationShadeWindowViewController,反之亦然

因为最近身体欠佳,加之已经开学,学业繁重,行文仓促,难免有些错误,忘看到的读者给予提醒,谢谢先。

补充:布局查看工具

读者可使用下面的工具,进行相应的布局查看

  1. 老版本DDMS,的hierarchy view
  2. Android Studio的YALI(通过插件市场安装)
  3. Android Studio的Legacy Layout Inspector(通过插件市场安装)

至于Android Studio自带的Layout Inspector就不推荐使用了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/103057.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【力扣】416. 分割等和子集 <动态规划、回溯>

【力扣】416. 分割等和子集 给你一个 只包含正整数的非空数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 示例 1&#xff1a; 输入&#xff1a;nums [1,5,11,5] 输出&#xff1a;true 解释&#xff1a;数组可以分割成 [1, 5,…

【Nacos】使用Nacos进行服务发现、配置管理

Nacos Nacos是 Dynamic Naming and Configuration Service 的首字母简称&#xff0c;一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 版本说明&#xff1a;版本说明 alibaba/spring-cloud-alibaba Wiki GitHub <properties><java.version>…

vue报错RangeError: Maximum call stack size exceeded

这种情况&#xff0c;一般是跳转路由时发生此类错误&#xff0c;像我的就是如此。比如路由指向的vue文件里代码有错误&#xff0c;或者设置路由时重定向了路由自己&#xff0c;造成死循环。 1、首先检查自己跳转的路由地址的代码本身是否有语法错误之类的&#xff0c;造成错误…

Python中的os模块:walk函数与listdir函数的深度解析

Python中的os模块&#xff1a;walk函数与listdir函数的深度解析 os.walk()函数listdir()函数使用场景案例一&#xff1a;遍历目录树并处理文件案例二&#xff1a;列出目录中的文件名并执行某些操作 总结 在Python中&#xff0c;os模块提供了许多与操作系统交互的功能&#xff0…

opencv案例06-基于opencv图像匹配的消防通道障碍物检测与深度yolo检测的对比

基于图像匹配的消防通道障碍物检测 技术背景 消防通道是指在各种险情发生时&#xff0c;用于消防人员实施营救和被困人员疏散的通道。消防法规定任何单位和个人不得占用、堵塞、封闭消防通道。事实上&#xff0c;由于消防通道通常缺乏管理&#xff0c;导致各种垃圾&#xff0…

(十九)大数据实战——Flume数据采集框架安装部署

前言 本节内容我们主要介绍一下大数据数据采集框架flume的安装部署&#xff0c;Flume 是一款流行的开源分布式系统&#xff0c;用于高效地采集、汇总和传输大规模数据。它主要用于处理大量产生的日志数据和事件流。Flume 支持从各种数据源&#xff08;如日志文件、消息队列、数…

【广州华锐互动】AR远程连接专家进行协同管理,解放双手让协同更便捷

AR远程协同系统是一种基于AR技术&#xff0c;实现远程设备维修和技术支持的系统。该系统通过将虚拟信息叠加在现实世界中&#xff0c;实现对设备的全方位监控和管理&#xff0c;并可以通过AR眼镜等终端设备&#xff0c;实时查看设备的各项数据和信息&#xff0c;为设备维修提供…

【算法日志】动态规划刷题:不相邻选择类问题(day40)

算法随想录刷题60Day 目录 前言 打家劫舍1 (数组) 打家劫舍2&#xff08;环形数组&#xff09; 打家劫舍3&#xff08;二叉树&#xff09; 前言 今天主要讨论不相邻选择类问题&#xff0c;会在不同数据结构题型的下探讨该类问题的解法。 打家劫舍1 (数组) 本题只需要讨论当…

HTML5+CSS3+JS小实例:科技感满满的鼠标移动推开粒子特效

实例:科技感满满的鼠标移动推开粒子特效 技术栈:HTML+CSS+JS 效果: 源码: 【html】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport&qu…

matlab绘制局部放大图

ZoomPlot是一个交互式的matlab局部绘图库&#xff0c;其github仓库地址为 https://github.com/iqiukp/ZoomPlot-MATLAB。在使用库之前需要先将库下载到本地&#xff0c;可以直接添加到matlab的库中&#xff0c;也可以放在项目文件中直接使用。 简单使用 其实使用这个库只需要…

Python|小游戏之猫捉老鼠!!!

最近闲(mang)来(dao)无(fei)事(qi)&#xff0c;喜欢研究一些小游戏&#xff0c;本篇文章我主要介绍使用 turtle 写的一个很简单的猫捉老鼠的小游戏&#xff0c;主要是通过鼠标控制老鼠(Tom)的移动&#xff0c;躲避通过电脑控制的猫(Jerry)的追捕。 游戏主体思考逻辑&#xff1…

stable diffusion实践操作-文生图

本文专门开一节写文生图相关的内容&#xff0c;在看之前&#xff0c;可以同步关注&#xff1a; stable diffusion实践操作 正文 1 liblib SD1.5底模 lora(baihuaniang_1.0) 详细信息&#xff1a; 底模&#xff1a;SD 1.5 Lora:baihuaniang_1.0 正向提示词&#xff1a; Best …

Kubernetes之舞:微服务的交响乐团

Kubernetes与微服务&#xff1a;缘起 微服务的崛起 微服务架构已经成为现代软件开发的标准。与传统的单体应用相比&#xff0c;微服务提供了更高的模块化&#xff0c;使得团队可以独立地开发、部署和扩展各个服务。这种架构模式的主要优势在于其灵活性和可扩展性&#xff0c;允…

后端SpringBoot+前端Vue前后端分离的项目(一)

前言&#xff1a;后端使用SpringBoot框架&#xff0c;前端使用Vue框架&#xff0c;做一个前后端分离的小项目&#xff0c;需求&#xff1a;实现一个表格&#xff0c;具备新增、删除、修改的功能。 目录 一、数据库表的设计 二、后端实现 环境配置 数据处理-增删改查 model…

python自动化测试-自动化基本技术原理

1 概述 在之前的文章里面提到过&#xff1a;做自动化的首要本领就是要会 透过现象看本质 &#xff0c;落实到实际的IT工作中就是 透过界面看数据。 掌握上面的这样的本领可不是容易的事情&#xff0c;必须要有扎实的计算机理论基础&#xff0c;才能看到深层次的本质东西。 …

【狂神】Spring5(Aop的实现方式)

今天没有偷懒&#xff0c;只是忘了Mybatis&#xff0c;所以去补课了~ ┏━━━━━━━━━━━━━━━┓ NICE PIGGY PIG.. ┗━━━━━━━△━━━━━━━┛ ヽ(&#xff65;ω&#xff65;)&#xff89; | / UU 1.Aop实现方式一 1.1、什…

基于Java的OA办公管理系统,Spring Boot框架,vue技术,mysql数据库,前台+后台,完美运行,有一万一千字论文。

基于Java的OA办公管理系统&#xff0c;Spring Boot框架&#xff0c;vue技术&#xff0c;mysql数据库&#xff0c;前台后台&#xff0c;完美运行&#xff0c;有一万一千字论文。 系统中的功能模块主要是实现管理员和员工的管理&#xff1b; 管理员&#xff1a;个人中心、普通员工…

FPGA优质开源项目 – UDP万兆光纤以太网通信

本文开源一个FPGA项目&#xff1a;UDP万兆光通信。该项目实现了万兆光纤以太网数据回环传输功能。Vivado工程代码结构和之前开源的《UDP RGMII千兆以太网》类似&#xff0c;只不过万兆以太网是调用了Xilinx的10G Ethernet Subsystem IP核实现。 下面围绕该IP核的使用、用户接口…

Linux入门之进程信号|信号产生的方式

文章目录 一、信号入门 1.linux信号的基本概念 2.使用kill -l 命令可以查看系统定义的信号列表 3.信号处理常见方式 二、产生信号 1.通过终端按键产生信号 2.通过调用系统函数向进程发信号 3.由软条件产生信号 4.硬件异常产生信号 1. /0异常 2.模拟野指针 一、信号入门…

操作系统备考学习 day2 (1.3.2 - 1.6)

操作系统备考学习 day2 计算机系统概述操作系统运行环境中断和异常的概念系统调用 操作系统体系结构操作系统引导虚拟机 计算机系统概述 操作系统运行环境 中断和异常的概念 中断的作用 CPU上会运行两种程序&#xff0c;一种是操作系统内核程序&#xff0c;一种是应用程序。…