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

news2025/1/25 17:54:12

背景:

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

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

分析套路和步骤:

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

TouchStates: <no displays touched>
  Display: 2
    logicalSize=1440x2960
        transform (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_UNTRUSTED
        transform (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_UNTRUSTED
        transform (ROT_0) (TRANSLATE)
            1.0000  0.0000  -0.0000
            0.0000  1.0000  -2792.0000
            0.0000  0.0000  1.0000
      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_UNTRUSTED
        transform (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_UNTRUSTED
        transform (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_UNTRUSTED
        transform (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_UNTRUSTED
        transform (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_UNTRUSTED
        transform (ROT_0) (SCALE TRANSLATE)
            0.3145  -0.0000  22.6451
            -0.0000  0.3145  46.5455
            0.0000  0.0000  1.0000
      7: 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_UNTRUSTED
        transform (ROT_0) (SCALE TRANSLATE)
            0.3145  -0.0000  22.6451
            -0.0000  0.3145  46.5455
            0.0000  0.0000  1.0000
  Display: 0
    logicalSize=1440x2960
        transform (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_UNTRUSTED
        transform (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_UNTRUSTED
        transform (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_UNTRUSTED
        transform (ROT_0) (TRANSLATE)
            1.0000  0.0000  -0.0000
            0.0000  1.0000  -2792.0000
            0.0000  0.0000  1.0000
      3: 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_UNTRUSTED
        transform (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_UNTRUSTED
        transform (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_UNTRUSTED
        transform (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_UNTRUSTED
        transform (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_UNTRUSTED
        transform (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_UNTRUSTED
        transform (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_UNTRUSTED
        transform (ROT_0) (SCALE TRANSLATE)
            0.3145  -0.0000  22.6451
            -0.0000  0.3145  46.5455
            0.0000  0.0000  1.0000
      10: 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_UNTRUSTED
        transform (ROT_0) (SCALE TRANSLATE)
            0.3145  -0.0000  22.6451
            -0.0000  0.3145  46.5455
            0.0000  0.0000  1.0000

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

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

  Display: 2
    logicalSize=1440x2960
        transform (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_UNTRUSTED
        transform (ROT_0) (IDENTITY)

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

Display: 0
    logicalSize=1440x2960
        transform (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_UNTRUSTED
        transform (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.coloradmin.cn/o/1426658.html

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

相关文章

算法篇之二分

二分算法简介 特点 最简单的一种算法&#xff0c;也是最恶心&#xff0c;细节最多&#xff0c;最容易写出死循环的算法时间复杂度O(logN) 如何学习 明白其中的算法原理&#xff0c;二分并不是只有数组有序的的时候使用&#xff0c;而是看是否具有二段性。模板 朴素的二分模…

算法面试八股文『 基础知识篇 』

博客介绍 近期在准备算法面试&#xff0c;网上信息杂乱不规整&#xff0c;出于强迫症就自己整理了算法面试常出现的考题。独乐乐不如众乐乐&#xff0c;与其奖励自己&#xff0c;不如大家一起嗨。以下整理的内容可能有不足之处&#xff0c;欢迎大佬一起讨论。 PS&#xff1a;…

失物招领|基于Springboot的校园失物招领系统设计与实现(源码+数据库+文档)

校园失物招领系统目录 目录 基于Springboot的校园失物招领系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、 管理员功能实现 (1) 失物招领管理 (2) 寻物启事管理 (3) 公告管理 (4) 公告类型管理 2、用户功能实现 (1) 失物招领 (2) 寻物启事 (3) 公告 …

2024 美国大学生数学建模竞赛 美赛(C题)网球比赛趋势问题 国际大学生数学建模竞赛| 建模秘籍文章代码思路大全

铛铛&#xff01;小秘籍来咯&#xff01; 小秘籍希望大家都能轻松建模呀&#xff0c;华数杯也会持续给大家放送思路滴~ 抓紧小秘籍&#xff0c;我们出发吧~ 完整内容可以在文章末尾领取&#xff01; 问题1 • 开发一个模型&#xff0c;捕捉到比赛进行时点的流动&#xff0c;…

(2)(2.11) RFD900

文章目录 前言 1 概述 2 主要功能 3 状态LED指示灯 4 接口 5 使用Mission Planner进行配置 6 支持不同国家/地区 7 讨论论坛 前言 RFD900 无线电调制解调器是一款高功率 900Mhz ISM 波段无线电调制解调器&#xff0c;设计用于远距离串行通信。据报道&#xff0c;其通信…

2024美国大学生数学建模美赛选题建议+初步分析

总的来说&#xff0c;去年算是美赛环境题元年&#xff0c;去年的开放度是较高的&#xff0c;今年每种赛题类型相对而言平均了起来 提示&#xff1a;DS C君认为的难度&#xff1a;E<BCF<AD&#xff0c;开放度&#xff1a;DBCE<A<F。 以下为A-F题选题建议及初步分析…

C++(17.5)——list模拟实现扩展

在上篇文章中&#xff0c;实现了的大部分功能以及部分迭代器。本片文章将对剩下的功能进行补充。 1. const迭代器&#xff1a; 对于上篇文章中实现的迭代器只能使用于非类型的对象。对于类型的遍历&#xff0c;则需要额外编写类型的迭代器。例如对于下面的场景&#xff1a; …

grafana安装DevOpsProdigy KubeGraf 1.5.2

安装DevOpsProdigy KubeGraf需要安装kube-state-metrics 官方地址&#xff1a;https://github.com/kubernetes/kube-state-metrics/tree/release-2.10/examples/standard 查看k8s版本和kube-state-metrics对应版本&#xff1a; [rootmaster1 kube-state-metrics]# ll 总用量 …

25考研|660/880/1000/1800全年带刷计划

作为一个参加过两次研究生考试的老学姐&#xff0c;我觉得考研数学的难度完全取决于你自己 我自己就是一个很好的例子 21年数学题目是公认的简单&#xff0c;那一年考130的很多&#xff0c;但是我那一年只考了87分。但是22年又都说是有史以来最难的一年&#xff0c;和20年的难度…

华擎B660 主板 怎么设置打开来电自启功能?

环境&#xff1a; 华擎B660 钢铁传奇 1700 : Intel B660 问题描述&#xff1a; 华擎B660 主板 怎么设置打开来电自启功能&#xff1f; 解决方案&#xff1a; 1.前往-高级- 芯片组配置 2.往下划找到交流 /电源断电恢复 选择电源故障后的电源状态。如果选择 [关机]&#x…

《PCI Express体系结构导读》随记 —— 第II篇 第4章 PCIe总线概述(4)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第II篇 第4章 PCIe总线概述&#xff08;3&#xff09; 4.1.2 PCIe总线使用的信号 PCIe设备使用两种电源信号供电&#xff0c;分别是Vcc与Vaux&#xff0c;其额定电压为3.3V。其中Vcc为主电源&#xff0c;PCIe设备…

免费分享一套SpringBoot+Vue药店(药房)管理系统,帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue药店(药房)管理系统 &#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue药店(药房)管理系统 Java毕业设计_哔哩哔哩_bilibili【免费】SpringBootVue药店(药房)管理系统 Java毕业设计…

flutter实战之美化 container

我们来看一个代码 Column(children: [...transaction.map((e) > Card(child:Row(children: [Container(child: Text(e.amout.toString()),),Column(children: [Text(e.title),Text(e.date.toString()),],)],),)).toList()],) 看看效果 感觉很不好 我们要去美化一下contai…

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)

专属领域论文订阅 关注{晓理紫|小李子}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 如果你感觉对你有所帮助&#xff0c;请关注我&#xff0c;每日准时为你推送最新论文。 为了答谢各位网友的支持&#xff0c;从今日起…

pytorch_car_caring 排坑记录

pytorch_car_caring 排坑记录 任务踩坑回顾简单环境问题代码版本问题症状描述解决方法 cuda问题&#xff08;异步问题&#xff09;症状描述解决方法 任务 因为之前那个MPC代码跑出来的效果不理想&#xff0c;看了一天代码&#xff0c;大概看明白了&#xff0c;但要做改进还要有…

力扣hot100 对称二叉树 递归

Problem: 101. 对称二叉树 文章目录 思路Code 思路 &#x1f468;‍&#x1f3eb; 参考 Code 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( n ) O(n) O(n) /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* …

Pytorch从零开始实战18

Pytorch从零开始实战——人脸图像生成 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——人脸图像生成环境准备模型定义开始训练可视化总结 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pytorch2.0.1cu118&#…

jmerter-01安装与界面介绍

文章目录 jmeter安装 jmeter安装 1.配置JDK环境 Jmeter到目前为止只支持java 8 2.解压JMeter安装包 就可以双击jmeter.bat 运行启动 3.运行过程中&#xff0c;不要关掉小黑窗 这个黑框不要关闭 jmeter图示

【CSS】外边距折叠(margin 塌陷)

外边距折叠(collapsing margins) 毗邻的两个或多个margin会合并成一个margin&#xff0c;叫做外边距折叠。 规则如下: 两个或多个毗邻的普通流中的块元素垂直方向上的 margin会折叠浮动元素 / inline-block元素 / 绝对定位元素 / 行内元素的margin不会和垂直方向上的其他元素…

使用Logstash将MySQL中的数据同步至Elasticsearch

目录 1 使用docker安装ELK 1.1 安装Elasticsearch 1.2 安装Kibana 1.3 安装Logstash 2 数据同步 2.1 准备MySQL表和数据 2.2 运行Logstash 2.3 测试 3 Logstash报错(踩坑)记录 3.1 记录一 3.1.1 报错信息 3.1.2 报错原因 3.1.3 解决方案 3.2 记录二 3.2.1 报错信…