Android 12系统源码_多屏幕(四)自由窗口模式

一、小窗模式

1.1 小窗功能的开启方式

  • 开发者模式下开启小窗功能
    在这里插入图片描述
  • adb 手动开启
adb shell settings put global enable_freeform_support  1
adb shell settings put global force_resizable_activities  1

1.2 源码配置

  • copy file
# add for freedom
PRODUCT_COPY_FILES += \frameworks/native/data/etc/android.software.freeform_window_management.xml:$(TARGET_COPY_OUT_SYSTEM)/etc/permissions/android.software.freeform_window_management.xml
  • overlay
    <!-- add for freeform --><bool name="config_freeformWindowManagement">true</bool>

1.3 小窗的启动方式

主要的启动方式,一个是多任务里面,点击应用图标,选择小窗模式,另一个是通过三方应用启动,比如侧边栏,通知栏等待。

  • 三方应用通过ActivityOptions 启动
    public void startFreeFormActivity(View view) {Intent intent = new Intent(this, FreeFormActivity.class);ActivityOptions options = ActivityOptions.makeBasic();options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);startActivity(intent, options.toBundle());}
  • 多任务启动
    通过长按应用图标,选择小窗模式,ActivityOptions 会设置 ActivityOptions#setLaunchWindowingMode 为 WINDOWING_MODE_FREEFORM,然后通过 ActivityManager#startActivity 启动 Activity。

frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java

public class ActivityTaskSupervisor implements RecentTasks.Callbacks {int startActivityFromRecents(int callingPid, int callingUid, int taskId,SafeActivityOptions options) {...代码省略...        }
}

1.4 应用兼容

应用需要设置 android:resizeableActivity=“true”,应用安装过程中会解析AndroidManifest.xml,并设置 PackageParser.ActivityInfo 的 privateFlags,在启动应用的时候,会根据 privateFlags 的值来判断是否支持小窗。

        if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity, true)) {ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;} else {ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;}} else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;}

1.5 基础的窗口信息

在Android 系统中,窗口是应用程序界面的基本单元,用于承载和显示应用的视图内容。每个 Activity 都有一个主窗口,但也可以有其他窗口,如对话框、悬浮窗等。

在应用上层的一些组件的体现上,变化不是很大,但是 Framework 中的对于窗口的管理,迭代变化一直都比较大,可能之前有的类,新的架构下就被精简了,所以主要掌握窗口的一些概念,这样比较容易在新的架构之下找到对应的实现。

这里先回顾一下基础的窗口和界面相关的概念:

  • Window(窗口): 窗口是应用程序界面的基本单元,用于承载和显示应用的视图内容。每个 Activity 都有一个主窗口,但也可以有其他窗口,如对话框、悬浮窗等。
  • WindowManagerService: 是 Android 系统中的窗口管理服务,负责管理窗口的创建、显示、移动、调整大小、层级关系等。它是 Android 窗口系统的核心组件。
  • View(视图): View 是 Android 中用户界面的基本构建块,用于在窗口中绘制和显示内容。它是窗口中可见元素的基础。
  • ViewGroup(视图组): ViewGroup 是一种特殊的 View,它可以包含其他视图(包括 View 和其他 ViewGroup)来形成复杂的用户界面。
  • Surface(表面): Surface 是用于绘制图形内容的区域,窗口和视图内容都可以在 Surface 上绘制。每个窗口通常对应一个 Surface。
  • SurfaceFlinger: 是 Android 系统中的一个组件,负责管理和合成窗口中的 Surface,以及在屏幕上绘制这些 Surface。
  • LayoutParams(布局参数): LayoutParams 是窗口或视图的布局参数,用于指定视图在其父视图中的位置、大小和外观等。
  • Window Token(窗口令牌): Window Token 是一个用于标识窗口所属于的应用程序或任务的对象。它在窗口的显示和交互中起着重要作用。
  • Window Decor(窗口装饰): Window Decor 是窗口的装饰元素,如标题栏、状态栏等,可以影响窗口的外观和交互。
  • Dialog(对话框): 对话框是一种特殊的窗口,用于在当前活动之上显示临时的提示、选择或输入内容。
  • Activity(活动): 在 Android 应用程序中,每个 Activity 都与一个 PhoneWindow 相关联。PhoneWindow 用于管理 Activity 的界面绘制和交互。
  • Window Callback(窗口回调): PhoneWindow 实现了 Window.Callback 接口,该接口用于处理窗口事件和交互。通过实现这个接口,您可以监听和响应窗口的状态变化、输入事件等。
  • DecorView(装饰视图): PhoneWindow 中的内容通常由 DecorView 承载。DecorView 是一个特殊的 ViewGroup,用于包含应用程序的用户界面内容和窗口装饰元素,如标题栏、状态栏等。
  • PhoneWindow(应用程序窗口): PhoneWindow 是 android.view.Window 类的实现之一,用于表示一个应用程序窗口。它提供了窗口的基本功能,如绘制、布局、装饰、焦点管理等。

1.6 窗口类型

frameworks/base/core/java/android/app/WindowConfiguration.java

public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> {public static final int WINDOWING_MODE_UNDEFINED = 0;public static final int WINDOWING_MODE_FULLSCREEN = 1;//全屏窗口模式public static final int WINDOWING_MODE_PINNED = 2;//固定窗口模式public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3;public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4;public static final int WINDOWING_MODE_FREEFORM = 5;//自由窗口模式public static final int WINDOWING_MODE_MULTI_WINDOW = 6;//多窗口模式/** @hide */@IntDef(prefix = { "WINDOWING_MODE_" }, value = {WINDOWING_MODE_UNDEFINED,WINDOWING_MODE_FULLSCREEN,WINDOWING_MODE_MULTI_WINDOW,WINDOWING_MODE_PINNED,WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,WINDOWING_MODE_FREEFORM,})public @interface WindowingMode {}
}

二、小窗的创建

小窗的创建时机有两块,一块是在页面创建的时候,也就是PhoneWindow创建的时候,会创建DecorView,DecorView 会判断是否要创立一个 DecorCaptionView。 另外一块当DecorView动态变化的时候,当有参数变量,经过onWindowSystemUiVisibilityChanged方法回调或者 onConfigurationChanged方法回调,系统会对DecorView 进行更新并判断是否需要新建一个小窗DecorCaptionView的视图。

2.1 页面创建的时候创建小窗

>frameworks/base/core/java/android/app/Activity.java
public class Activity extends ContextThemeWrapperimplements LayoutInflater.Factory2,Window.Callback, KeyEvent.Callback,OnCreateContextMenuListener, ComponentCallbacks2,Window.OnWindowDismissedCallback,ContentCaptureManager.ContentCaptureClient {public void setContentView(View view) {//注释1,调用PhoneWindow的setContentView方法getWindow().setContentView(view);initWindowDecorActionBar();}}>frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java  
public class PhoneWindow extends Window implements MenuBuilder.Callback {private DecorView mDecor;ViewGroup mContentParent;@Overridepublic void setContentView(View view, ViewGroup.LayoutParams params) {if (mContentParent == null) {//注释2,调用installDecorinstallDecor();} ...代码省略...}private void installDecor() {...代码省略...//注释3,创建窗口对应的DecorView视图mDecor = generateDecor(-1);...代码省略...//注释4,调用generateLayout方法mContentParent = generateLayout(mDecor);            }protected ViewGroup generateLayout(DecorView decor) {...代码省略...//注释5,调用DecorView的onResourcesLoaded方法mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);  ...代码省略...          }
}>frameworks/base/core/java/com/android/internal/policy/DecorView.java
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {//加载应用需要的布局资源void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {...代码省略...//创建小窗视图mDecorCaptionView = createDecorCaptionView(inflater);//应用需要加载的根布局final View root = inflater.inflate(layoutResource, null);if (mDecorCaptionView != null) {//注释6,如果小窗视图不为空,则将小窗的视图添加到DecorView中if (mDecorCaptionView.getParent() == null) {addView(mDecorCaptionView,new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));}//然后将应用根布局添加到mDecorCaptionView中mDecorCaptionView.addView(root,new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));} else {//注释7,如果不是小窗,则将应用根布局添加到DecorView中addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));}mContentRoot = (ViewGroup) root;initializeElevation();}private DecorCaptionView createDecorCaptionView(LayoutInflater inflater) {DecorCaptionView decorCaptionView = null;for (int i = getChildCount() - 1; i >= 0 && decorCaptionView == null; i--) {View view = getChildAt(i);if (view instanceof DecorCaptionView) {// The decor was most likely saved from a relaunch - so reuse it.decorCaptionView = (DecorCaptionView) view;removeViewAt(i);}}final WindowManager.LayoutParams attrs = mWindow.getAttributes();final boolean isApplication = attrs.type == TYPE_BASE_APPLICATION ||attrs.type == TYPE_APPLICATION || attrs.type == TYPE_DRAWN_APPLICATION;final WindowConfiguration winConfig = getResources().getConfiguration().windowConfiguration;// Only a non floating application window on one of the allowed workspaces can get a captionif (!mWindow.isFloating() && isApplication && winConfig.hasWindowDecorCaption()) {// Dependent on the brightness of the used title we either use the// dark or the light button frame.if (decorCaptionView == null) {//调用inflateDecorCaptionView方法decorCaptionView = inflateDecorCaptionView(inflater);}decorCaptionView.setPhoneWindow(mWindow, true /*showDecor*/);} else {decorCaptionView = null;}enableCaption(decorCaptionView != null);return decorCaptionView;}private DecorCaptionView inflateDecorCaptionView(LayoutInflater inflater) {final Context context = getContext();inflater = inflater.from(context);//注释8,构建小窗对应的布局文件final DecorCaptionView view = (DecorCaptionView) inflater.inflate(R.layout.decor_caption,null);setDecorCaptionShade(view);return view;}
}

如上所示Activity的setContentView方法经过层层调用最终会触发DecorView的onResourcesLoaded方法,如果是小窗模式,会走到注释6处,将页面需要的布局资源添加到DecorCaptionView中,然后将DecorCaptionView添加到DecorView中;如果是普通应用场景,会走到注释7处,会将布局资源添加到DecorView中;最终WMS会将DecorView添加到屏幕上。另外在注释8处可以看到小窗加载的是什么布局资源。

2.2 在DecorView的回调方法中创建小窗

public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {@Overridepublic void onWindowSystemUiVisibilityChanged(int visible) {updateColorViews(null /* insets */, true /* animate */);//调用updateDecorCaptionStatus方法更新小窗的状态updateDecorCaptionStatus(getResources().getConfiguration());if (mStatusGuard != null && mStatusGuard.getVisibility() == VISIBLE) {updateStatusGuardColor();}}@Overrideprotected void onConfigurationChanged(Configuration newConfig) {super.onConfigurationChanged(newConfig);//调用updateDecorCaptionStatus方法更新小窗的状态updateDecorCaptionStatus(newConfig);initializeElevation();}private void updateDecorCaptionStatus(Configuration config) {//如果定义窗口类型为小窗,且不是全屏模式, 则创建一个DecorCaptionView在DecorView内部。final boolean displayWindowDecor = config.windowConfiguration.hasWindowDecorCaption()&& !isFillingScreen(config);if (mDecorCaptionView == null && displayWindowDecor) {// Configuration now requires a caption.final LayoutInflater inflater = mWindow.getLayoutInflater();//注释1,调用createDecorCaptionView方法创建小窗视图mDecorCaptionView = createDecorCaptionView(inflater);if (mDecorCaptionView != null) {if (mDecorCaptionView.getParent() == null) {addView(mDecorCaptionView, 0,new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));}removeView(mContentRoot);mDecorCaptionView.addView(mContentRoot,new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));}} else if (mDecorCaptionView != null) {//注释2,如果已经创建了 DecorCaptionView, 则更新配置信息,比如窗口大小,窗口位置等。mDecorCaptionView.onConfigurationChanged(displayWindowDecor);// 是否显示小窗的标题栏enableCaption(displayWindowDecor);}}
}

在DecorView的onWindowSystemUiVisibilityChanged回调方法和onConfigurationChanged回调方法中,都会进一步调用updateDecorCaptionStatus方法;然后如果判断需要创建小窗且小窗还未被创建,则在注释1处,会调用createDecorCaptionView方法创建小窗视图;否则在注释2处,调用DecorCaptionView的onConfigurationChanged方法通知小窗进行配置变化。

三、小窗的实现

2.2 小窗的标题栏

frameworks/base/core/java/com/android/internal/widget/DecorCaptionView.java

public class DecorCaptionView extends ViewGroup implements View.OnTouchListener,GestureDetector.OnGestureListener {private View mCaption;  // 标题栏private View mContent; // 小窗View之下,应用的根Viewprivate View mMaximize; // 最大化按钮private View mClose; // 关闭按钮
}

2.3 触摸事件

public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {//如果在应用的小窗View外部点击的话,直接将事件拦截掉,这样就不会触发应用的点击事件。@Overridepublic boolean onInterceptTouchEvent(MotionEvent event) {int action = event.getAction();//是否显示小窗标题栏if (mHasCaption && isShowingCaption()) {//如果窗口可调整大小,并且事件是(开始)在小窗外部,则不要将 ACTION_DOWN 事件进行传递。窗口调整大小事件应由WindowManager处理。if (action == MotionEvent.ACTION_DOWN) {final int x = (int) event.getX();final int y = (int) event.getY();if (isOutOfInnerBounds(x, y)) {return true;}}}...代码省略...return false;}
}

frameworks/base/core/java/com/android/internal/widget/DecorCaptionView.java

public class DecorCaptionView extends ViewGroup implements View.OnTouchListener,GestureDetector.OnGestureListener {private View mClickTarget;@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {//如果用户点击最大化或者关闭按钮,就拦截事件,这样就不会触发应用的点击事件if (ev.getAction() == MotionEvent.ACTION_DOWN) {final int x = (int) ev.getX();final int y = (int) ev.getY();//Only offset y for containment tests because the actual views are already translated.//是否点击到最大化按钮的区域if (mMaximizeRect.contains(x, y - mRootScrollY)) {mClickTarget = mMaximize;}//是否点击到关闭按钮的区域if (mCloseRect.contains(x, y - mRootScrollY)) {mClickTarget = mClose;}}return mClickTarget != null;}}

在小窗的View中,应用就不能通过View的事件来直接处理,DecorCaptionView 需要通过计算View所在的矩形区域,然后计算点击的区域是否处于该矩形区域范围内判断为点击,就是一个点和面的问题,原生小窗上的问题就是这个触控面太小,手指的点击区域可能不容易触发。 (在我开发的ChatDev游戏中,也有面和面碰撞的问题,玩家的位置和碰撞位置的计算)

2.4 小窗的边界

目前国内的厂商的小窗设计,都是通过在DecorView里面模仿DecorCaptionView自定义一个View,用来作为小窗内部应用的容器。

  • 边界圆角 一般会对这个小窗容器进行一个UI上的美化,主要的一个就是边界的圆角轮廓绘制。

  • 导航栏重叠的问题

DisplayPolicy 作为系统里面控制显示 dock栏、状态栏、导航栏的样式的主要类, 在每次绘制布局之后,都会走到如下applyPostLayoutPolicyLw 函数,进行显示规则的条件,当判断重叠之后,在导航栏更新透明度规则的时候,将其标记中不透明的纯深色背景和浅色前景清空。

public class DisplayPolicy {public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,WindowState attached, WindowState imeTarget) {final boolean affectsSystemUi = win.canAffectSystemUiFlags();if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);applyKeyguardPolicy(win, imeTarget);// 检查自由窗口是否与导航栏区域重叠。final boolean isOverlappingWithNavBar = isOverlappingWithNavBar(win);if (isOverlappingWithNavBar && !mIsFreeformWindowOverlappingWithNavBar&& win.inFreeformWindowingMode()) {// 如果窗口是自由窗口,并且窗口和导航栏重叠mIsFreeformWindowOverlappingWithNavBar = true;}if (!affectsSystemUi) {return;}...代码省略...}}

💡 技术无价,赞赏随心

写文不易,如果本文帮你避开了“八小时踩坑”,或者让你直呼“学到了!”
欢迎扫码赞赏,让我知道这篇内容值得!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# 将HTML文档、HTML字符串转换为图片

在.NET开发中&#xff0c;将HTML内容转换为图片的需求广泛存在于报告生成、邮件内容存档、网页快照等场景。Free Spire.Doc for .NET作为一款免费的专业文档处理库&#xff0c;无需Microsoft Word依赖&#xff0c;即可轻松实现这一功能。本文将深入解析HTML文档和字符串转图片两…

【HTML-15.2】HTML表单按钮全面指南:从基础到高级实践

表单按钮是网页交互的核心元素&#xff0c;作为用户提交数据、触发操作的主要途径&#xff0c;其重要性不言而喻。本文将系统性地介绍HTML表单按钮的各种类型、使用场景、最佳实践以及高级技巧&#xff0c;帮助开发者构建更高效、更易用的表单交互体验。 1. 基础按钮类型 1.1…

吴恩达MCP课程(4):connect_server_mcp_chatbot

目录 完整代码代码解释1. 导入和初始化2. 类型定义3. MCP_ChatBot 类初始化4. 查询处理 (process_query)5. 服务器连接管理6. 核心特性总结 示例 完整代码 原课程代码是用Anthropic写的&#xff0c;下面代码是用OpenAI改写的&#xff0c;模型则用阿里巴巴的模型做测试 .env 文…

C++内存学习

引入 在实例化对象时&#xff0c;不管是编译器还是我们自己&#xff0c;会使用构造函数给成员变量一个合适的初始值。 但是经过构造函数之后&#xff0c;我们还不能将其称为成员变量的初始化&#xff1a; 构造函数中的语句只能称为赋初值&#xff0c;而不能称作初始化 因为初…

MySQL 大战 PostgreSQL

一、底层架构对比 ​​维度​​​​MySQL​​​​PostgreSQL​​​​存储引擎​​多引擎支持&#xff08;InnoDB、MyISAM等&#xff09;单一存储引擎&#xff08;支持扩展如Zheap、Zedstore&#xff09;​​事务实现​​基于UNDO日志的MVCC基于堆表(Heap)的MVCC​​锁机制​​…

基于FPGA的二叉决策树cart算法verilog实现,训练环节采用MATLAB仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) MATLAB训练结果 上述决策树判决条件&#xff1a; 分类的决策树1 if x21<17191.5 then node 2 elseif x21>17191…

【RAG】RAG综述|一文了解RAG|从零开始(下)

文章目录 5. RAG的架构5.1 Naive RAG5.2 Advanced RAG5.2.1 检索前处理和数据索引技术5.2.2 知识分片技术5.2.3 分层索引5.2.4 检索技术5.2.4.1 优化用户查询5.2.4.2 通过假想文档嵌入修复查询和文档不对称5.2.4.3 Routing5.2.4.5 自查询检索5.2.4.6 混合搜索5.2.4.7 图检索5.2…

山东大学软件学院项目实训-基于大模型的模拟面试系统-面试官和面试记录的分享功能(2)

本文记录在发布文章时&#xff0c;可以添加自己创建的面试官和面试记录到文章中这一功能的实现。 前端 首先是在原本的界面的底部添加了两个多选框&#xff08;后期需要美化调整&#xff09; 实现的代码&#xff1a; <el-col style"margin-top: 1rem;"><e…

FPGA纯verilog实现MIPI-DSI视频编码输出,提供工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我这里已有的 MIPI 编解码方案 3、设计思路框架工程设计原理框图FPGA内部彩条RGB数据位宽转换RGB数据缓存MIPI-DSI协议层编码MIPI-DPHY物理层串化MIPI-LVDS显示屏工程…

LXQt修改开始菜单高亮

开始菜单红色高亮很难看 mkdir -p ~/.local/share/lxqt/palettes/ mkdir -p ~/.local/share/lxqt/themes/ cp /usr/share/lxqt/palettes/Dark ~/.local/share/lxqt/palettes/Darker cp -p /usr/share/lxqt/themes/dark ~/.local/share/lxqt/themes/darker lxqt-panel.qss L…

DeepSeek-R1-0528-Qwen3-8B 本地ollama离线运行使用和llamafactory lora微调

参考: https://huggingface.co/deepseek-ai/DeepSeek-R1-0528-Qwen3-8B 量化版本: https://huggingface.co/unsloth/DeepSeek-R1-0528-Qwen3-8B-GGUF https://docs.unsloth.ai/basics/deepseek-r1-0528-how-to-run-locally 1、ollama运行 升级ollama版本到0.9.0 支持直接…

vue3 + WebSocket + Node 搭建前后端分离项目 开箱即用

[TOC](vue3 WebSocket Node 搭建前后端分离项目) 开箱即用 前言 top1&#xff1a;vue3.5搭建前端H5 top2&#xff1a;Node.js koa搭建后端服务接口 top3&#xff1a;WebSocket 长连接实现用户在线聊天 top4&#xff1a;接口实现模块化 Mysql 自定义 top5&#xff1a;文件上…

Vue 前端代码规范实战:ESLint v9、Prettier 与 Stylelint 集成指南与最佳实践

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template &#x1f33a; 仓库主页&#xff1a; GitCode︱ Gitee ︱ Github &#x1f496; 欢迎点赞 &#x1f44d; 收藏 ⭐评论 …

docker docker-ce docker.io

Ubuntu安装 ​​更新软件包列表​​ 首先确保软件包列表是最新的&#xff1a; sudo apt-get update 使用正确的卸载命令​​ 替换 docker-engine 为 docker-ce 或 docker.io&#xff1a; sudo apt-get remove docker docker-ce docker.io containerd runc ​​检查已安装的 Do…

C++ 初阶 | 类和对象易错知识点(下)

目录 0.引言 1.初始化列表 2.static 静态成员变量&#xff1a; 静态成员函数&#xff1a; 3.友元函数 4.内部类 定义&#xff1a; 特点&#xff1a; 应用&#xff1a; 5.优化写法 6.例题 求和12...n (不能用for/while/if/else等关键字) 7.总结 0.引言 今天&…

使用yocto搭建qemuarm64环境

环境 yocto下载 # 源码下载 git clone git://git.yoctoproject.org/poky git reset --hard b223b6d533a6d617134c1c5bec8ed31657dd1268 构建 # 编译镜像 export MACHINE"qemuarm64" . oe-init-build-env bitbake core-image-full-cmdline 运行 # 跑虚拟机 export …

AWS WebRTC:获取ICE服务地址(part 3):STUN服务和TURN服务的作用

STUN服务和TURN服务的作用&#xff1a; 服务全称作用是否中继流量适用场景STUNSession Traversal Utilities for NAT 协助设备发现自己的公网地址&#xff08;srflx candidate&#xff09; ❌ 不中继&#xff0c;仅辅助NAT 穿透成功时使用TURNTraversal Using Relays around N…

分析XSSstrike源码

#用于学习web安全自动化工具# 我能收获什么&#xff1f; 1.XSS漏洞检测机制 学习如何构造和发送XSS payload如何识别响应中的回显&#xff0c;WAF&#xff0c;过滤规则等如何使用词典&#xff0c;编码策略&#xff0c;上下文探测等绕过过滤器 2.Python安全工具开发技巧 使…

npm run build 报错:Some chunks are larger than 500 KB after minification

当我们的 Vue 项目太大&#xff0c;使用 npm run build 打包项目的时候&#xff0c;就有可能会遇到以下报错&#xff1a; (!) Some chunks are larger than 500 kB after minification. Consider: - Using dynamic import() to code-split the application - Use build.rollup…

【LLM相关知识点】关于LLM项目实施流程的简单整理(一)

【LLM相关知识点】关于LLM项目实施流程的简单整理&#xff08;一&#xff09; 文章目录 【LLM相关知识点】关于LLM项目实施流程的简单整理&#xff08;一&#xff09;零、学习计划梳理&#xff1a;结合ChatGPT从零开始学习LLM & 多模态大模型一、大模型相关应用场景和头部企…