MirrorLayer可以正常触摸屏幕原理分析

背景:

上次blog分享了给学员朋友们布置的作业,今天来进行简单的揭秘。

问题:
在多屏互动时候有一个屏幕的画面是一个MirrorLayer,另一个屏幕画面是真实的,即2个屏幕上有一个是MirrorLayer,这个时候疑问就来了,经过在aosp13上体验发现,两个屏幕画面都可以正常接受触摸事件进行正常的事件响应。
在这里插入图片描述

分析套路和步骤:

和触摸相关第一时间是分析input相关的信息:
adb shell dumpsys input
核心信息如下:

TouchStates: <no displays touched>Display: 2logicalSize=1440x2960transform (ROT_0) (IDENTITY)Windows:0: name='e5e3fdf PointerLocation - display 2', id=137, displayId=2, inputConfig=NO_INPUT_CHANNEL | NOT_FOCUSABLE | NOT_TOUCHABLE | PREVENT_SPLITTING | TRUSTED_OVERLAY, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)1: name='642754 NavigationBar2', id=146, displayId=2, inputConfig=NOT_FOCUSABLE | TRUSTED_OVERLAY | WATCH_OUTSIDE_TOUCH | SLIPPERY, alpha=1.00, frame=[0,2792][1440,2960], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[166,2792][442,2960]|[580,2792][860,2960], ownerPid=742, ownerUid=10098, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (TRANSLATE)1.0000  0.0000  -0.00000.0000  1.0000  -2792.00000.0000  0.0000  1.00002: name='a0396ce com.android.messaging/com.android.messaging.ui.appsettings.ApplicationSettingsActivity', id=217, displayId=2, inputConfig=0x0, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=ActivityRecord{363f04d u0 com.android.messaging/.ui.appsettings.ApplicationSettingsActivity} t32}, applicationInfo.token=0x7f37d78fa730, touchableRegion=[0,0][1440,2960], ownerPid=1596, ownerUid=10084, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)3: name='3411b77 ActivityRecordInputSink com.android.messaging/.ui.appsettings.ApplicationSettingsActivity', id=231, displayId=2, inputConfig=NO_INPUT_CHANNEL | NOT_FOCUSABLE | NOT_TOUCHABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)4: name='598595e ActivityRecordInputSink com.android.messaging/.ui.conversationlist.ConversationListActivity', id=160, displayId=2, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)5: name='2754cb8 ActivityRecordInputSink com.android.launcher3/.secondarydisplay.SecondaryDisplayLauncher', id=132, displayId=2, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)6: name='Wallpaper BBQ wrapper#140', id=140, displayId=2, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE, alpha=1.00, frame=[-71,-147][2860,3108], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=742, ownerUid=10098, dispatchingTimeout=5000ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (SCALE TRANSLATE)0.3145  -0.0000  22.6451-0.0000  0.3145  46.54550.0000  0.0000  1.00007: name='c0e9fea com.android.systemui.ImageWallpaper', id=139, displayId=2, inputConfig=NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE | PREVENT_SPLITTING | IS_WALLPAPER, alpha=1.00, frame=[-71,-147][-71,-147], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=742, ownerUid=10098, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (SCALE TRANSLATE)0.3145  -0.0000  22.6451-0.0000  0.3145  46.54550.0000  0.0000  1.0000Display: 0logicalSize=1440x2960transform (ROT_0) (IDENTITY)Windows:0: name='StrictModeFlash', id=47, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE | PREVENT_SPLITTING | TRUSTED_OVERLAY, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=0, ownerUid=0, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)1: name='e997ecb PointerLocation - display 0', id=50, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_FOCUSABLE | NOT_TOUCHABLE | PREVENT_SPLITTING | TRUSTED_OVERLAY, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)2: name='da1cb67 NavigationBar0', id=77, displayId=0, inputConfig=NOT_FOCUSABLE | TRUSTED_OVERLAY | WATCH_OUTSIDE_TOUCH | SLIPPERY, alpha=1.00, frame=[0,2792][1440,2960], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[166,2792][442,2960]|[580,2792][860,2960]|[996,2792][1273,2960], ownerPid=742, ownerUid=10098, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (TRANSLATE)1.0000  0.0000  -0.00000.0000  1.0000  -2792.00000.0000  0.0000  1.00003: name='621c16b StatusBar', id=78, displayId=0, inputConfig=NOT_FOCUSABLE | TRUSTED_OVERLAY, alpha=1.00, frame=[0,0][1440,84], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[0,0][1440,84], ownerPid=742, ownerUid=10098, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)4: name='a0396ce com.android.messaging/com.android.messaging.ui.appsettings.ApplicationSettingsActivity', id=219, displayId=0, inputConfig=0x0, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=ActivityRecord{363f04d u0 com.android.messaging/.ui.appsettings.ApplicationSettingsActivity} t32}, applicationInfo.token=0x7f37d78fa730, touchableRegion=[0,0][1440,2960], ownerPid=1596, ownerUid=10084, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)5: name='3411b77 ActivityRecordInputSink com.android.messaging/.ui.appsettings.ApplicationSettingsActivity', id=232, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_FOCUSABLE | NOT_TOUCHABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)6: name='598595e ActivityRecordInputSink com.android.messaging/.ui.conversationlist.ConversationListActivity', id=175, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_VISIBLE | NOT_FOCUSABLE | NOT_TOUCHABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)7: name='80c19b3 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher', id=179, displayId=0, inputConfig=NOT_FOCUSABLE | DUPLICATE_TOUCH_TO_WALLPAPER, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=ActivityRecord{19be992 u0 com.android.launcher3/.uioverrides.QuickstepLauncher} t29}, applicationInfo.token=0x7f37d78bc210, touchableRegion=[0,0][1440,2960], ownerPid=1078, ownerUid=10096, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)8: name='98e4748 ActivityRecordInputSink com.android.launcher3/.uioverrides.QuickstepLauncher', id=105, displayId=0, inputConfig=NO_INPUT_CHANNEL | NOT_FOCUSABLE, alpha=1.00, frame=[0,0][0,0], globalScale=0.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=[-14399,-29599][14400,29600], ownerPid=552, ownerUid=1000, dispatchingTimeout=0ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)9: name='Wallpaper BBQ wrapper#83', id=83, displayId=0, inputConfig=NO_INPUT_CHANNEL, alpha=1.00, frame=[-71,-147][2860,3108], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=742, ownerUid=10098, dispatchingTimeout=5000ms, hasToken=false, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (SCALE TRANSLATE)0.3145  -0.0000  22.6451-0.0000  0.3145  46.54550.0000  0.0000  1.000010: name='55a8a23 com.android.systemui.ImageWallpaper', id=82, displayId=0, inputConfig=NOT_FOCUSABLE | NOT_TOUCHABLE | PREVENT_SPLITTING | IS_WALLPAPER, alpha=1.00, frame=[-71,-147][-71,-147], globalScale=1.000000, applicationInfo.name=, applicationInfo.token=<null>, touchableRegion=<empty>, ownerPid=742, ownerUid=10098, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (SCALE TRANSLATE)0.3145  -0.0000  22.6451-0.0000  0.3145  46.54550.0000  0.0000  1.0000

因为dump input信息较多,一般我们只关注相关window的部分,这个部分就是代表了每个屏幕的window有哪些在接受触摸事件,一般是上到下顺序依次寻找接受事件。

可以明显看到无论是display 2还是display 0都是有对相关的短信Activity的图层
display 2明显有ApplicationSettingsActivity的对应windowInfo

  Display: 2logicalSize=1440x2960transform (ROT_0) (IDENTITY)Windows:2: name='a0396ce com.android.messaging/com.android.messaging.ui.appsettings.ApplicationSettingsActivity', id=217, displayId=2, inputConfig=0x0, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=ActivityRecord{363f04d u0 com.android.messaging/.ui.appsettings.ApplicationSettingsActivity} t32}, applicationInfo.token=0x7f37d78fa730, touchableRegion=[0,0][1440,2960], ownerPid=1596, ownerUid=10084, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)

display 0也明显有ApplicationSettingsActivity的对应windowInfo,而且和上面display2的windowinfo是同一个对象(name='a0396ce 这个可以看出)

Display: 0logicalSize=1440x2960transform (ROT_0) (IDENTITY)Windows:4: name='a0396ce com.android.messaging/com.android.messaging.ui.appsettings.ApplicationSettingsActivity', id=219, displayId=0, inputConfig=0x0, alpha=1.00, frame=[0,0][1440,2960], globalScale=1.000000, applicationInfo.name=ActivityRecord{363f04d u0 com.android.messaging/.ui.appsettings.ApplicationSettingsActivity} t32}, applicationInfo.token=0x7f37d78fa730, touchableRegion=[0,0][1440,2960], ownerPid=1596, ownerUid=10084, dispatchingTimeout=5000ms, hasToken=true, touchOcclusionMode=BLOCK_UNTRUSTEDtransform (ROT_0) (IDENTITY)

到这里就可以理解为啥两个屏幕各自的mirrorlayer和正常layer都可以正常接受触摸事件的原因,因为在input派发选择窗口,遍历window时候,都对应是同一个windowinfo。
为啥可以实现在input层中两个sf的layer都是对应同一个windowinfo呢?这个部分就需要深入分析sf部分的源码
在这里插入图片描述

不同display的Layer对应相同windowinfo

分析一下sf中mirrorLayer的源码实现


status_t SurfaceFlinger::mirrorLayer(const LayerCreationArgs& args,const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle,int32_t* outLayerId) {ATRACE_CALL();if (!mirrorFromHandle) {return NAME_NOT_FOUND;}sp<Layer> mirrorLayer;sp<Layer> mirrorFrom;{status_t result = createContainerLayer(args, outHandle, &mirrorLayer);mirrorLayer->setClonedChild(mirrorFrom->createClone());}*outLayerId = mirrorLayer->sequence;return addClientLayer(args.client, *outHandle, mirrorLayer /* layer */, nullptr /* parent */,false /* addToRoot */, nullptr /* outTransformHint */);
}

创建好根部mirrorLayer,且把mirrorFrom也创建了一个Clone Layer,作为mirrorLayer的child,但是并没有对mirrorFrom的Child Layer进行相关的创建,相当于现在只有个最顶层的mirrorFrom的mirror如下:

在这里插入图片描述
如上图所示,只有个Task的Mirror,但是Task下面的ActivityRecord等并没有进行创建,得等到下一次vsync来时

void Layer::updateMirrorInfo() {ATRACE_FORMAT("%s updateMirrorInfo",mName.c_str());//省略mClonedChild->updateClonedDrawingState(clonedLayersMap);mClonedChild->updateClonedChildren(this, clonedLayersMap);mClonedChild->updateClonedRelatives(clonedLayersMap);
}

这里updateClonedChildren会导致最后相关Children Layer进行createClone

sp<Layer> BufferStateLayer::createClone() {LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata());args.textureName = mTextureName;sp<BufferStateLayer> layer = mFlinger->getFactory().createBufferStateLayer(args);layer->mHwcSlotGenerator = mHwcSlotGenerator;layer->setInitialValuesForClone(this);return layer;
}

这里有个核心方法setInitialValuesForClone

void BufferLayer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {Layer::setInitialValuesForClone(clonedFrom);sp<BufferLayer> bufferClonedFrom = static_cast<BufferLayer*>(clonedFrom.get());mPremultipliedAlpha = bufferClonedFrom->mPremultipliedAlpha;mPotentialCursor = bufferClonedFrom->mPotentialCursor;mProtectedByApp = bufferClonedFrom->mProtectedByApp;updateCloneBufferInfo();
}

这里会调用到updateCloneBufferInfo方法

mirrorLayer时候会进行全部信息的克隆拷贝模式,包含了这次分析最重要的windowInfo信息:

在这里插入图片描述

可以看到mirror的mDrawingState的inputInfo信息相当于是完全从real layer中拷贝过来的。

这里的inputInfo就是最为关键的信息,也就是最后传递给input端的关键点

传递WindowInfo的补充

在updateInputFlinger时候会进行windowInfos集合信息填充
在这里插入图片描述接下来看看这里buildWindowInfos
在这里插入图片描述这里看看fillInputInfo方法
在这里插入图片描述
可以看到其实这里就是把前面的的inputInfo最后通过updateInputFlinger中的跨进程调用到了InputDispatcher中去了

本文章对应视频手把手教你学framework:
hal+perfetto+surfaceflinger
https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
在这里插入图片描述

私聊作者+v(androidframework007)

七件套专题:在这里插入图片描述
点击这里 https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw

视频:https://www.bilibili.com/video/BV1wc41117L4/

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

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

相关文章

【C++基础入门】四、程序流程结构(水仙花数、乘法口诀、七和七的倍数、随机数猜数字)

四、程序流程结构 C/C支持最基本的三种程序运行结构&#xff1a;顺序结构、选择结构、循环结构 顺序结构&#xff1a;程序按顺序执行&#xff0c;不发生跳转选择结构&#xff1a;依据条件是否满足&#xff0c;有选择的执行相应功能循环结构&#xff1a;依据条件是否满足&…

Virtual DOM的实现原理

Virtual DOM的实现原理 课程目标 了解什么是虚拟DOM,以及虚拟DOM的作用Snabbdom的基本使用&#xff08;Vue内部的虚拟Dom是改造了开源库Snabbdom&#xff09;Snabbdom的源码解析 在面试的时候经常会问到虚拟DOM是怎么工作的&#xff0c;通过查看Snabbdom源码&#xff0c;可以…

机器学习---半监督学习(基于分岐的方法)

1. 基于分歧的方法 与生成式方法、半监督SVM、图半监督学习等基于单学习器利用未标记数据不同&#xff0c;基于分歧的方 法(disagreement--based methods)使用多学习器&#xff0c;而学习器之间的“分歧”(disagreement)对未标记 数据的利用至关重要。 1.2 协同训练 “协同…

实验一 古典密码算法的设计与实现

✅作者简介&#xff1a;CSDN内容合伙人、信息安全专业在校大学生&#x1f3c6; &#x1f525;系列专栏 &#xff1a;简单外包单 &#x1f4c3;新人博主 &#xff1a;欢迎点赞收藏关注&#xff0c;会回访&#xff01; &#x1f4ac;舞台再大&#xff0c;你不上台&#xff0c;永远…

猫什么时候发腮?猫咪发腮指南!这些生骨肉冻干发腮效果好

猫什么时候发腮是许多猫主人非常关心的问题。在猫咪的成长过程中&#xff0c;发腮是一项重要的体征&#xff0c;也是猫咪成熟的标志。主人需要在适龄的年龄段加强营养补给&#xff0c;可以让让猫咪拥有可爱的肉嘟嘟脸型&#xff0c;不要错失最佳发腮期。那么&#xff0c;什么时…

花瓣网美女图片爬取

爬虫基础案例01 花瓣网美女图片 网站url&#xff1a;https://huaban.com 图片爬取 import requests import json import os res requests.get(url "https://api.huaban.com/search/file?text%E7%BE%8E%E5%A5%B3&sortall&limit40&page1&positionsear…

【论文阅读笔记】Advances in 3D Generation: A Survey

Advances in 3D Generation: A Survey 挖个坑&#xff0c;近期填完摘要 time&#xff1a;2024年1月31日 paper&#xff1a;arxiv 机构&#xff1a;腾讯 挖个坑&#xff0c;近期填完 摘要 生成 3D 模型位于计算机图形学的核心&#xff0c;一直是几十年研究的重点。随着高级神经…

第96讲:MySQL高可用集群MHA的核心概念以及集群搭建

文章目录 1.MHA高可用数据库集群的核心概念1.1.主从复制架构的演变1.2.MHA简介以及架构1.3.MHA的软件结构1.4.MHA Manager组件的启动过程1.5.MHA高可用集群的原理 2.搭建MHA高可用数据库集群2.1.环境架构简介2.2.搭建基于GTID的主从复制集群2.2.1.在三台服务器中分别搭建MySQL实…

Prometheus 企业级监控使用总结

一、监控概念&误区 监控是管理基础设施和业务的核心工具&#xff0c;监控应该和应用程序一起构建和部署&#xff0c;没有监控&#xff0c;将无法了解你的系统运行环境&#xff0c;进行故障诊断&#xff0c;也无法阻止提供系统性的性能、成本和状态等信息。 误区&#xff…

法兰缺损零件设计加工替换盾构机扫描建模厂家抄数修图出CAD图纸

在现代工业生产中&#xff0c;法兰缺损零件的问题时有发生&#xff0c;这不仅会影响设备的正常运行&#xff0c;还会给企业带来巨大的经济损失。为了解决这一问题&#xff0c;CASAIM中科广电三维扫描和3D打印设计加工技术的运用成为了关键。 首先&#xff0c;CASAIM中科广电需要…

“与客户,共昂首”——Anzo Capital昂首资本尽释行业进取之姿

“以匠心&#xff0c;铸不凡” 活动的现场&#xff0c;Anzo Capital 作为演讲嘉宾分享“以匠心&#xff0c;铸不凡”的产品理念。Anzo Capital积淀九载&#xff0c;匠心打造出“STP”和“ECN”两大核心账户&#xff0c;以光之速度将交易中的订单直达市场和流动性提供商&#…

Unity通过物理带动实现传输带运输物品

前言&#xff1a;遇到个听起来挺简单的需求&#xff0c;就是实现一个传输带&#xff0c;传输物品。但细想发现如果是直接设置物品的速度&#xff0c;或者通过设置父物体的方式带动物品&#xff0c;都挺不好&#xff0c;关联性太强。最后选择用到一个很实用的API, Rigidbody.M…

Vue+OpenLayers7入门到实战:OpenLayers7加载天地图

返回《Vue+OpenLayers7》专栏目录:Vue+OpenLayers7 前言 本章介绍如何使用OpenLayers7在地图上加载天地图. 天地图瓦片访问需要先到天地图申请key。天地图官网链接 本文使用xyz方式加载天地图,并且介绍如何加载xyz格式天地图url,包括天地图纯底图(无标记)、卫星影像图…

SpringMVC入门学习(十)----mvc:annotation-driven标签介绍

目录 1、关于mvc:annotation-driven作用2、mvc:annotation-driven在什么时候必须配置3、关于mvc:annotation-driven配合使用的几种情况 回到顶部 1、关于mvc:annotation-driven作用 [1]、<mvc:annotation-driven /> 会自动向容器中注册如下组件&#xff0c;并且会代替…

0101appscan安装与使用入门-扫描-信息收集

1 简介 HCL AppScan&#xff08;原IBM Security AppScan&#xff09;是原IBM的Rational软件部门的一组网络安全测试和监控工具&#xff0c;2019年被HCL技术公司收购。AppScan旨在在开发过程中对Web应用程序的安全漏洞进行测试[1]。该产品学习每个应用程序的行为&#xff0c;无…

【蓝桥杯51单片机入门记录】LED

目录 一、基础 &#xff08;1&#xff09;新建工程 &#xff08;2&#xff09;编写前准备 二、LED &#xff08;1&#xff09;点亮LED灯 &#xff08;2&#xff09;LED闪烁 延时函数的生成&#xff08;stc-isp中生成&#xff09; 实现 &#xff08;3&#xff09;流水灯…

MG7050HAN 基于声表的差分多输出 晶体振荡器 (HCSL)

基于MG7050 HAN的声表差分多输出晶体振荡器(HCSL)&#xff0c;采用两路或四路差分HCSL&#xff08;高速电流驱动逻辑&#xff09;输出&#xff0c;可以减少外部扇出缓冲区&#xff0c;特别适用于需要超低抖动、高频率范围内稳定工作的应用场合。其输出特性曲线超低抖动&#xf…

降维(Dimensionality Reduction)

一、动机一&#xff1a;数据压缩 这节我将开始谈论第二种类型的无监督学习问题&#xff0c;称为降维。有几个原因使我们可能想要做降维&#xff0c;其一是数据压缩&#xff0c;它不仅允许我们压缩数据使用较少的计算机内存或磁盘空间&#xff0c;而且它可以加快我们的学习算法。…

90年代的黄河路,大家都在用什么方式互相联络?

1992 年的上海&#xff0c;霓虹养眼&#xff0c;万花如海… 新年伊始&#xff0c;一部《繁花》爆火出圈&#xff0c;带观众穿越回了那个灯红酒绿的上海。90 年代的黄河路遍地是机会&#xff0c;商业战场上&#xff0c;信息成了最宝贵的财富&#xff0c;谁能获得最真实有用的资讯…

Python学习之路-DRF基础:视图

Python学习之路-DRF基础:视图 视图概览 简介 REST framework 提供了众多的通用视图基类与扩展类&#xff0c;以简化视图的编写。 视图的继承关系 视图的方法与属性 视图说明 两个基类 APIView 简介 rest_framework.views.APIView APIView是REST framework提供的所有视…