frameworks 之 Activity添加View
frameworks 之 Activity添加View
- 1 LaunchActivityItem
- 1.1 Activity 创建
- 1.2 PhoneWindow 创建
- 1.3 DecorView 创建
- 2 ResumeActivityItem
讲解 Activity加载View的时机和流程
涉及到的类如下
- frameworks/base/core/java/android/app/Activity.java
- frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
- frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
- frameworks/base/core/java/android/view/WindowManagerImpl.java
从之前文章Activity启动流程可知,最终会到 ActivityTaskSupervisor 的 realStartActivityLocked 方法,而 realStartActivityLocked 最终会执行 2个主要步骤 就是 LaunchActivityItem 和 ResumeActivityItem。
1 LaunchActivityItem
1.1 Activity 创建
LaunchActivityItem 的 又会调用 ActivityThread的 handleLaunchActivity 方法
public void execute(ClientTransactionHandler client, IBinder token,PendingTransactionActions pendingActions) {Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");ActivityClientRecord r = client.getLaunchingActivity(token);client.handleLaunchActivity(r, pendingActions, null /* customIntent */);Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);}
handleLaunchActivity 又会调用 performLaunchActivity 方法
public Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) {...final Activity a = performLaunchActivity(r, customIntent);...return a;}
performLaunchActivity 方法中
- 会通过反射调用对应的 Activity
- 调用 Activity的 attach 方法创建phoneWindow
- 通过 callActivityOnCreate 执行 Activity的 onCreate方法
- 设置 ActivityClientRecord 状态为 ON_CREATE
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {...ContextImpl appContext = createBaseContextForActivity(r);// 进行反射创建对应的 Activity对象Activity activity = null;try {java.lang.ClassLoader cl = appContext.getClassLoader();activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);StrictMode.incrementExpectedActivityCount(activity.getClass());r.intent.setExtrasClassLoader(cl);r.intent.prepareToEnterProcess(isProtectedComponent(r.activityInfo),appContext.getAttributionSource());if (r.state != null) {r.state.setClassLoader(cl);}} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to instantiate activity " + component+ ": " + e.toString(), e);}}try {Application app = r.packageInfo.makeApplication(false, mInstrumentation);if (activity != null) {...// 调用 attach方法创建对应的的phoneView和 windowMangerImplactivity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.configCallback,r.assistToken, r.shareableActivityToken);...r.activity = activity;// 触发Activity的 onCreate方法if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}...}// 设置 ActivityRecord状态为 ON_CREATEr.setState(ON_CREATE);} catch (SuperNotCalledException e) {throw e;} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to start activity " + component+ ": " + e.toString(), e);}}return activity;}
1.2 PhoneWindow 创建
查看上面 Attach 方法
- 创建了 PhoneWindow
- 调用 phoneWindow的setWindowManager 方法 创建对应 WindowManagerImpl 对象。
- 将创建的WindowManagerImpl 赋值给 mWindowManager
final void attach(Context context, ActivityThread aThread...) {...// 初始化 PhoneWindowmWindow = new PhoneWindow(this, window, activityConfigCallback);...// 初始化 并设置WindowManager到phoneWindow对应的变量mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),mToken, mComponent.flattenToString(),(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);if (mParent != null) {mWindow.setContainer(mParent.getWindow());}// 将上一步通过 setWindowManager 创建WindowManagerImpl并赋值给 mWindowManagermWindowManager = mWindow.getWindowManager();
}
1.3 DecorView 创建
执行了 Activity onCreate 方法后 ,我们就会对其调用 setContentView 将要显示的布局ID创建创建视图,setContentView 方法又会调用 phoneWindow的setContentView方法
public void setContentView(@LayoutRes int layoutResID) {getWindow().setContentView(layoutResID);initWindowDecorActionBar();}
phoneWindow的setContentView主要做了
- 判断 mContentParent 是否为空(放应用要显示的布局容器),为空的话 则调用 installDecor 方法,创建 DecorView 和 内容容器 mContentParent
- 调用 inflate 将布局加载到 mContentParent 布局容器中
public void setContentView(int layoutResID) {// 如果contentview为空则加载decorViewif (mContentParent == null) {installDecor();} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {mContentParent.removeAllViews();}if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,getContext());transitionTo(newScene);} else {// 将对应的布局加载到对应的内容区域mLayoutInflater.inflate(layoutResID, mContentParent);}...}
其中 installDecor 方法主要逻辑
- 判断 mDecor 是否为空 ,为空的话调用 generateDecor 方法**(直接new DecorView),,并赋值**
- 判断 mContentParent 是否为空,为空的话 调用 generateLayout() 方法获取对应的容器.(里面会通过feature 加载对应的布局,然后获取R.id.content的控件),并返回。
- 根据属性 设置对应的标题。
private void installDecor() {mForceDecorInstall = false;// 为空则创建 DecorViewif (mDecor == null) {mDecor = generateDecor(-1);mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);mDecor.setIsRootNamespace(true);if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);}} else {mDecor.setWindow(this);}// 为空则获取 decorView 用布局加载好里面的id为content的viewgroupif (mContentParent == null) {mContentParent = generateLayout(mDecor);...mTitleView = findViewById(R.id.title);if (mTitleView != null) {if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {final View titleContainer = findViewById(R.id.title_container);if (titleContainer != null) {titleContainer.setVisibility(View.GONE);} else {mTitleView.setVisibility(View.GONE);}mContentParent.setForeground(null);} else {mTitleView.setText(mTitle);}}}}}
generateLayout 主要
- 获取一系列属性
- 调用 getLocalFeatures 生成对应的 features,根据获取到的属性获取对应的布局ID赋值到 layoutResource
- 调用 decorView 的 onResourcesLoaded 方法 inflage出对应的布局,并通过 addView添加到 decorView,赋值给对应的mContentRoot 属性。
- 根据mDecorView获取ID为 R.id.content的内容容器,并返回出去
protected ViewGroup generateLayout(DecorView decor) {...// 获取设置一系列属性mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)& (~getForcedWindowFlags());...// Inflate the window decor.// 获取对应的 layout布局文件int layoutResource;int features = getLocalFeatures();// System.out.println("Features: 0x" + Integer.toHexString(features));if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {if (mIsFloating) {TypedValue res = new TypedValue();getContext().getTheme().resolveAttribute(R.attr.dialogTitleIconsDecorLayout, res, true);layoutResource = res.resourceId;} else {layoutResource = R.layout.screen_title_icons;}// XXX Remove this once action bar supports these features.removeFeature(FEATURE_ACTION_BAR);// System.out.println("Title Icons!");} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {// Special case for a window with only a progress bar (and title).// XXX Need to have a no-title version of embedded windows.layoutResource = R.layout.screen_progress;// System.out.println("Progress!");} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {// Special case for a window with a custom title.// If the window is floating, we need a dialog layoutif (mIsFloating) {TypedValue res = new TypedValue();getContext().getTheme().resolveAttribute(R.attr.dialogCustomTitleDecorLayout, res, true);layoutResource = res.resourceId;} else {layoutResource = R.layout.screen_custom_title;}// XXX Remove this once action bar supports these features.removeFeature(FEATURE_ACTION_BAR);} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {// If no other features and not embedded, only need a title.// If the window is floating, we need a dialog layoutif (mIsFloating) {TypedValue res = new TypedValue();getContext().getTheme().resolveAttribute(R.attr.dialogTitleDecorLayout, res, true);layoutResource = res.resourceId;} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {layoutResource = a.getResourceId(R.styleable.Window_windowActionBarFullscreenDecorLayout,R.layout.screen_action_bar);} else {layoutResource = R.layout.screen_title;}// System.out.println("Title!");} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {layoutResource = R.layout.screen_simple_overlay_action_mode;} else {// Embedded, so no decoration is needed.layoutResource = R.layout.screen_simple;// System.out.println("Simple!");}mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);// 根据mDecorView获取ID为 R.id.contentViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);if (contentParent == null) {throw new RuntimeException("Window couldn't find content container view");}...return contentParent;}
2 ResumeActivityItem
经过 onCreate 视图view都创建准备好后,就会进入 resume阶段
ResumeActivityItem 又会执行对应的 handleResumeActivity 方法。
public void execute(ClientTransactionHandler client, ActivityClientRecord r,PendingTransactionActions pendingActions) {Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");// 执行 ActivityThread 的 handleResumeActivityclient.handleResumeActivity(r, true /* finalStateRequest */, mIsForward,"RESUME_ACTIVITY");Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);}
handleResumeActivity 方法
- 从 ActivityClientRecord 取出 创建的 Activity,。将 decorView 设置为 INVISIBLE,
- 将对应的 LayoutParams type 层级设置为 WindowManager.LayoutParams.TYPE_BASE_APPLICATION
- 调用 phoneWindow 创建的 WindowManagerImpl(attach创建) ,调用 addView 将 decorView添加到 WMS中。
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,boolean isForward, String reason) {...final Activity a = r.activity;...final int forwardBit = isForward? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;// If the window hasn't yet been added to the window manager,// and this guy didn't finish itself or start another activity,// then go ahead and add the window.boolean willBeVisible = !a.mStartedActivity;if (!willBeVisible) {willBeVisible = ActivityClient.getInstance().willActivityBeVisible(a.getActivityToken());}if (r.window == null && !a.mFinished && willBeVisible) {// 赋值 phoneWindow 给ActivityClientRecordr.window = r.activity.getWindow();View decor = r.window.getDecorView();decor.setVisibility(View.INVISIBLE);ViewManager wm = a.getWindowManager();WindowManager.LayoutParams l = r.window.getAttributes();// 将 decor赋值给activitya.mDecor = decor;// 设置Activity的层级为applicationl.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;l.softInputMode |= forwardBit;...// 将decorView 通过 wms添加到容器中if (a.mVisibleFromClient) {if (!a.mWindowAdded) {a.mWindowAdded = true;wm.addView(decor, l);} }}}
WindowManagerImpl 添加时候 又会调用 全局单例WindowManagerGlobal 添加
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {applyTokens(params);mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,mContext.getUserId());}
addView中 会调用
- 创建对应的 ViewRootImpl
- 将对应参数添加到各自的数组中
- 调用 ViewRootImpl 的 setVIew 开始执行添加视图的 3步曲 (addToDisplayAsUser, relayout, finishDraw)
public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow, int userId) {if (view == null) {throw new IllegalArgumentException("view must not be null");}if (display == null) {throw new IllegalArgumentException("display must not be null");}if (!(params instanceof WindowManager.LayoutParams)) {throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");}final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;// 如果不为空则认为子窗口添加,通过 adjustLayoutParamsForSubWindow 补全对应的参数 如title 和 tokenif (parentWindow != null) {parentWindow.adjustLayoutParamsForSubWindow(wparams);} else {// If there's no parent, then hardware acceleration for this view is// set from the application's hardware acceleration setting.final Context context = view.getContext();if (context != null&& (context.getApplicationInfo().flags& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;}}// 创建对应的 ViewRootImplViewRootImpl root;View panelParentView = null;synchronized (mLock) {// Start watching for system property changes.if (mSystemPropertyUpdater == null) {mSystemPropertyUpdater = new Runnable() {@Override public void run() {synchronized (mLock) {for (int i = mRoots.size() - 1; i >= 0; --i) {mRoots.get(i).loadSystemProperties();}}}};SystemProperties.addChangeCallback(mSystemPropertyUpdater);}// 从 mViews 获取该view是否已添加int index = findViewLocked(view, false);if (index >= 0) {// 判断该view是否在移除if (mDyingViews.contains(view)) {// Don't wait for MSG_DIE to make it's way through root's queue.mRoots.get(index).doDie();} else {throw new IllegalStateException("View " + view+ " has already been added to the window manager.");}// The previous removeView() had not completed executing. Now it has.}// If this is a panel window, then find the window it is being// attached to for future reference.if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {final int count = mViews.size();for (int i = 0; i < count; i++) {if (mRoots.get(i).mWindow.asBinder() == wparams.token) {panelParentView = mViews.get(i);}}}// 创建viewRootImpl,该方法会通过 WindowManagerGlobal.getWindowSession() 获取sessionroot = new ViewRootImpl(view.getContext(), display);view.setLayoutParams(wparams);// 添加到对应的数组mViews.add(view);mRoots.add(root);mParams.add(wparams);// do this last because it fires off messages to start doing thingstry {root.setView(view, wparams, panelParentView, userId);} catch (RuntimeException e) {// BadTokenException or InvalidDisplayException, clean up.if (index >= 0) {removeViewLocked(index, true);}throw e;}}}
这样完成了Activity View的加载。
相关文章:
frameworks 之 Activity添加View
frameworks 之 Activity添加View 1 LaunchActivityItem1.1 Activity 创建1.2 PhoneWindow 创建1.3 DecorView 创建 2 ResumeActivityItem 讲解 Activity加载View的时机和流程 涉及到的类如下 frameworks/base/core/java/android/app/Activity.javaframeworks/base/services/cor…...
UWB技术中的两种调制方式:PPM与PAM
Ultra-Wideband (UWB) 技术以其低功耗、宽频谱和高精度定位的特点,广泛应用于物联网(IoT)、智能家居、资产追踪和无线通信等领域。在UWB中,信号的调制方式对于数据传输的效率和精度起着至关重要的作用。本文将深入探讨UWB中常用的…...
达梦:用户和模式
目录标题 数据库管理系统与用户权限管理**四权分立****用户管理与权限划分****用户管理界面与权限控制****用户创建与管理****实操**1. **默认创建用户与模式**:2. **用户权限和角色分配**:3. **命令行管理用户与角色**:4. 模式也可以创建 **…...
23. AI-大语言模型-DeepSeek
文章目录 前言一、DeepSeek是什么1. 简介2. 产品版本3. 特征4. 地址链接5. 三种访问方式1. 网页端和APP2. DeepSeek API 二、DeepSeek可以做什么1. 应用场景2. 文本生成1. 文本创作2. 摘要与改写3. 结构化生成 3. 自然语言理解与分析1. 语义分析2. 文本分类3. 知识推理 4. 编程…...
Spring-GPT智谱清言AI项目(附源码)
一、项目介绍 本项目是Spring AI第三方调用整合智谱请言(官网是:https://open.bigmodel.cn)的案例,回答响应流式输出显示,这里使用的是免费模型,需要其他模型可以去 https://www.bigmodel.cn/pricing 切换…...
计算机网络(涵盖OSI,TCP/IP,交换机,路由器,局域网)
一、网络通信基础 (一)网络通信的概念 网络通信是指终端设备之间通过计算机网络进行的信息传递与交流。它类似于现实生活中的物品传递过程:数据(物品)被封装成报文(包裹),通过网络…...
云计算架构学习之Ansible-playbook实战、Ansible-流程控制、Ansible-字典循环-roles角色
一、Ansible-playbook实战 1.Ansible-playbook安装软件 bash #编写yml [rootansible ansible]# cat wget.yml - hosts: backup tasks: - name: Install wget yum: name: wget state: present #检查playbook的语法 [rootansible ansible]…...
《运维工程师如何利用DeepSeek实现智能运维:分级实战指南》
目录 智能运维革命:DeepSeek带来的范式转变DeepSeek核心运维能力全景解析分级实战场景与解决方案 3.1 初级工程师:自动化运维入门3.2 中级工程师:复杂系统诊断与优化3.3 高级工程师:架构级智能运维典型项目案例深度剖析 4.1 金融系统全链路监控体系构建4.2 电商大促资源弹性…...
windows事件倒计时器与提醒组件
widgets 这是桌面组件前端开源组件,作者称:项目还在持续完善中,目前包含键盘演示、抖音热榜、喝水提醒、生日列表、待办事项、倒计时、灵动通知、打工进度等多个组件 有vue编程能力的可以自己做组件 百度网盘 夸克网盘 桌面组件 | Ca…...
Mac OS JAVA_HOME设置
个人博客地址:Mac OS JAVA_HOME设置 | 一张假钞的真实世界 在MacOS上使用DMG文件安装了Jdk8 之后,在默认路径下找不到JDK的HOME路径: $ which java /usr/bin/java $ ls -l /usr/bin/java lrwxr-xr-x 1 root wheel 74 12 6 2015 /usr/b…...
6.3 DBMS的功能和特征
文章目录 DBMS的6大功能DBMS的3个特征DBMS的分类 DBMS的6大功能 DBMS包含数据定义,数据库操作(检索、插入、修改、删除),数据库运行管理(保证多用户环境下正常运行),数据组织、存储、管理&…...
C# ConcurrentQueue 使用详解
总目录 前言 在C#多线程编程中,数据共享如同走钢丝——稍有不慎就会引发竞态条件(Race Condition)或死锁。传统Queue<T>在并发场景下需要手动加锁,而ConcurrentQueue<T>作为.NET Framework 4.0 引入的线程安全集合&a…...
python脚本文件设置进程优先级(在.py文件中实现)
在 Python 代码中可以直接通过 psutil 模块或 系统调用 来设置进程优先级,无需依赖终端命令。以下是具体方法和示例: 1. 使用 psutil 模块(跨平台推荐) psutil 是一个跨平台库,支持 Windows、Linux 和 macOS。通过其 …...
基于Django快递物流管理可视化分析系统(完整系统源码+数据库+详细开发文档+万字详细论文+答辩PPT+详细部署教程等资料)
文章目录 基于Django快递物流管理可视化分析系统(完整系统源码数据库详细开发文档万字详细论文答辩PPT详细部署教程等资料)一、项目概述二、项目说明三、研究意义四、系统设计技术架构 五、功能实现六、完整系统源码数据库详细开发文档万字详细论文答辩P…...
el-table树状表格,默认展开第一个节点的每一层
效果如图 <template><el-table:data"tableData"style"width: 100%":tree-props"{ children: children, hasChildren: hasChildren }":expand-row-keys"expandRowKeys"row-key"id"expand-change"handleExpan…...
【雅思博客05】New Guy in Town
Daily Life ‐ New Guy in Town 原文: A: Oh, I don’t know if you heard, but someone moved into that old house down the road. B: Yeah, I know. I met the owner of the house yesterday as he was moving in. His name is Armand. A: Really? What’s h…...
【Spring详解三】默认标签的解析
三、默认标签的解析 Spring的标签中有 默认标签和 自定义标签,两者的解析有着很大的不同,这次重点说默认标签的解析过程。 DefaultBeanDefinitionDocumentReader.class 默认标签的解析是在 DefaultBeanDefinitionDocumentReader.parseDefaultElement()函…...
Windows 图形显示驱动开发-IoMmu 模型
输入输出内存管理单元 (IOMMU) 是一个硬件组件,它将支持具有 DMA 功能的 I/O 总线连接到系统内存。 它将设备可见的虚拟地址映射到物理地址,使其在虚拟化中很有用。 在 WDDM 2.0 IoMmu 模型中,每个进程都有一个虚拟地址空间,即&a…...
简单易懂,解析Go语言中的Channel管道
Channel 管道 1 初始化 可用var声明nil管道;用make初始化管道; len(): 缓冲区中元素个数, cap(): 缓冲区大小 //变量声明 var a chan int //使用make初始化 b : make(chan int) //不带缓冲区 c : make(chan stri…...
STM32 USB 设备的描述信息作用
在使用 STM32 USB 功能时 usbd_desc.c 文件中定义了一段宏,以下解每段宏的用途。 #define USBD_VID 1155 #define USBD_LANGID_STRING 1033 #define USBD_MANUFACTURER_STRING "STMicroelectronics" #define US…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
