当前位置: 首页 > news >正文

HarmonyOS开发实例:【分布式邮件】

概述

基于TS扩展的声明式开发范式编程语言编写的一个分布式邮件系统,可以由一台设备拉起另一台设备,每次改动邮件内容,都会同步更新两台设备的信息。效果图如下:

搭建OpenHarmony开发环境

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以Hi3516DV300开发板为例,参照以下步骤进行:

  1. [获取OpenHarmony系统版本]:标准系统解决方案(二进制)。

    以3.0版本为例:

  2. 搭建烧录环境。

    1. [完成DevEco Device Tool的安装]
    2. [完成Hi3516开发板的烧录]
    3. 鸿蒙开发指导:gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击复制转到打开。
  3. 搭建开发环境。

    1. 开始前请参考[工具准备],完成DevEco Studio的安装和开发环境配置。
    2. 开发环境配置完成后,请参考[使用工程向导]创建工程(模板选择“Empty Ability”),选择JS或者eTS语言开发。
    3. 工程创建完成后,选择使用[真机进行调测]。
      2.鸿蒙HarmonyOS与OpenHarmony技术知识籽料+mau123789是v直接拿

搜狗高速浏览器截图20240326151450.png

分布式组网

本章节以系统自带的音乐播放器为例,介绍如何完成两台设备的分布式组网。

  1. 硬件准备:准备两台烧录相同的版本系统的Hi3516DV300开发板A、B、一根网线及TYPE-C转USB线。

  2. 保证开发板A、B上电开机状态,网线两端分别连接开发板A、B的网口,将TYPE-C转USB线先连接A,使用hdc_std.exe,在命令行输入hdc_std shell ifconfig eth0 192.168.3.125,设置成功后,将TYPE-C转USB线连接B,在命令行输入hdc_std shell ifconfig eth0 192.168.3.126即可。

  3. 将设备A,B设置为互相信任的设备。

    • 找到系统应用“音乐”。

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • 设备A打开音乐,点击左下角流转按钮,弹出列表框,在列表中会展示远端设备的id。

    • 选择远端设备B的id,另一台开发板(设备B)会弹出验证的选项框。

    • 设备B点击允许,设备B将会弹出随机PIN码,将设备B的PIN码输入到设备A的PIN码填入框中。

    配网完毕。

代码结构解读

本篇Codelab只对核心代码进行讲解,首先来介绍下整个工程的代码结构:

  • MainAbility:存放应用主页面。

    • pages/index.ets:应用主页面。
  • model:存放获取组网内的设备列表相关文件。

    • RemoteDeviceModel.ets:获取组网内的设备列表。
  • ServiceAbility:存放ServiceAbility相关文件。

    • service.ts:service服务,用于跨设备连接后通讯。
  • resources :存放工程使用到的资源文件。

    • resources/rawfile:存放工程中使用的图片资源文件。
  • config.json:配置文件。

实现页面布局和样式

在本章节中,您将学会如何制作一个简单的邮件界面。

  1. 实现主页面布局和样式。

    • 在MainAbility/pages/index.ets 主界面文件中布局整个邮件页面,包括收件人、发件人、主题、内容等等,代码如下:

      @Entry
      @Component
      struct Index {private imageList: any[]= []@Provide dataList: string[]= ['xiaohua@128.com','xiaoming@128.com','假期温馨提示','2022年新春佳节即将来临,请同学们细读节前相关温馨提示,保持办公场所环境整洁,假期期间注意信息及个人安全,预祝全体同学新春快乐,虎虎生威!']dialogController: CustomDialogController = new CustomDialogController({builder: CustomDialogExample({ cancel: this.onCancel, confirm: this.onAccept }),cancel: this.existApp,autoCancel: true})build() {Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween }) {Column() {Row() {Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {Text('✕').fontSize(20).fontColor('#000000')Button('发送').width(70).fontSize(14).fontColor('#ffffff').backgroundColor('#fc4646').onClick(() => {RegisterDeviceListCallback();this.dialogController.open();})}.height(50).padding({ top: 10, right: 15, bottom: 10, left: 15 })}Column() {Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {Text('收件人').width(70).height(30).fontSize(15).fontColor('#969393')Text(this.dataList[0]).width('100%').height(30).fontSize(15).fontColor('#000000')}.padding({ top: 5, right: 15, bottom: 5, left: 15 })Text().width('100%').height(1).backgroundColor('#f8f6f6')Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {Text('发件人').width(70).height(30).fontSize(15).fontColor('#969393')Text(this.dataList[1]).width('100%').height(30).fontSize(15).fontColor('#000000')}.padding({ top: 5, right: 15, bottom: 5, left: 15 })Text().width('100%').height(1).backgroundColor('#f8f6f6')Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {Text('主题').width(50).height(30).fontSize(15).fontColor('#969393')Text(this.dataList[2]).width('100%').height(30).fontSize(15).fontColor('#000000')}.padding({ top: 5, right: 15, bottom: 5, left: 15 })Text().width('100%').height(1).backgroundColor('#f8f6f6')TextArea({ placeholder: 'input your word', text: this.dataList[3]}).height('100%').width('100%').onChange((value: string) => {this.dataList[3] = valueif(mRemote){sendMessageToRemoteService(JSON.stringify(this.dataList));}onDisconnectService();})}}Column() {Flex({ direction: FlexDirection.Row }) {List() {ForEach(this.imageList, (item) => {ListItem() {Image(item).width(50).height(50).objectFit(ImageFit.Contain)}.editable(true)}, item => item)}.listDirection(Axis.Horizontal) // 排列方向.divider({ strokeWidth: 2, color: 0xFFFFFF, startMargin: 20, endMargin: 20 }) // 每行之间的分界线}.width('100%').height(50).backgroundColor('#ccc')Text().width('100%').height(1).backgroundColor('#f8f6f6')Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween }) {Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) {Button({ stateEffect: false }) {Image($rawfile('icon_photo.png')).width(20).height(20)}.backgroundColor('#ffffff').margin({ right: 20 }).onClick(() => {RegisterDeviceListCallback();this.dialogController.open();})Button({ stateEffect: false }) {Image($rawfile('icon_at.png')).width(20).height(20)}.backgroundColor('#ffffff')}Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.End }) {Button({ stateEffect: false }) {Image($rawfile('icon_distributed.png')).width(20).height(20)}.backgroundColor('#ffffff').onClick(() => {this.getDeviceList()})Button({ stateEffect: false }) {Image($rawfile('icon_timer.png')).width(20).height(20)}.backgroundColor('#ffffff').margin({ left: 10, right: 10 })Button({ stateEffect: false }) {Image($rawfile('icon_enclosure.png')).width(20).height(20)}.backgroundColor('#ffffff')}}.height(50).padding(15)}}.width('100%').padding({ top: 5, bottom: 15 })}
      }
      

      在入口组件的生命周期函数aboutToAppear()中调用订阅事件。如果Ability是被其他设备拉起的,在aboutToAppear()中调用featureAbility.getWant(),可通过want中的参数重新初始化dataList数组,入口组件的生命周期函数aboutToAppear()代码如下:

      async aboutToAppear() {this.subscribeEvent();let self = this;// 当被拉起时,通过want传递的参数同步对端界面UIawait featureAbility.getWant((error, want) => {var status = want.parameters;if (want.parameters.dataList) {self.dataList = JSON.parse(status.dataList)// 远端被拉起后,连接对端的serviceif (want.parameters.remoteDeviceId) {let remoteDeviceId = want.parameters.remoteDeviceIdonConnectRemoteService(remoteDeviceId)}}});}
      
  2. 给"发送"按钮添加点击事件。

    点击"发送"按钮,调用拉起弹窗函数,弹窗中显示可拉起的同局域网下的设备,代码如下:

    Button('发送').width(70).fontSize(14).fontColor('#ffffff').backgroundColor('#fc4646').onClick(() => {RegisterDeviceListCallback();this.dialogController.open();})
    
  3. 给内容区域Textarea添加onChange事件。

    内容区域文字变化会调用onChange()方法,每一次的变化都会调用sendMessageToRemoteService()方法去同步另一个设备的数据。其中onChange()和sendMessageToRemoteService()方法代码如下:

    TextArea({ placeholder: 'input your word', text: this.dataList[3]}).height('100%').width('100%').onChange((value: string) => {this.dataList[3] = valueif(mRemote){sendMessageToRemoteService(JSON.stringify(this.dataList));}onDisconnectService();})
    
      async function sendMessageToRemoteService(dataList) {if (mRemote == null) {prompt.showToast({message: "mRemote is null"});return;}let option = new rpc.MessageOption();let data = new rpc.MessageParcel();let reply = new rpc.MessageParcel();data.writeStringArray(JSON.parse(dataList));prompt.showToast({message: "sendMessageToRemoteService" + dataList,duration: 3000});await mRemote.sendRequest(1, data, reply, option);let msg = reply.readInt();}
    

拉起远端FA及连接远端Service服务

在本章节中,您将学会如何拉起在同一组网内的设备上的FA,并且连接远端Service服务。

  1. 调用featureAbility.startAbility()方法,拉起远端FA,并同步界面UI。

    点击"分布式拉起"按钮,调用RegisterDeviceListCallback()发现设备列表,并弹出设备列表选择框CustomDialogExample,选择设备后拉起远端FA。CustomDialogExample()代码如下:

    // 设备列表弹出框
    @CustomDialog
    struct CustomDialogExample {@State editFlag: boolean = false@Consume imageIndexForPosition : number[]@Consume pictureList: string[]controller: CustomDialogControllercancel: () => voidconfirm: () => voidbuild() {Column() {List({ space: 10, initialIndex: 0 }) {ForEach(DeviceIdList, (item) => {ListItem() {Row() {Text(item).width('87%').height(50).fontSize(10).textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF).onClick(() => {onStartRemoteAbility(item,this.imageIndexForPosition,this.pictureList);this.controller.close();})Radio({value:item}).onChange((isChecked) => {onStartRemoteAbility(item,this.imageIndexForPosition,this.pictureList);this.controller.close();}).checked(false)}}.editable(this.editFlag)}, item => item)}}.width('100%').height(200).backgroundColor(0xDCDCDC).padding({ top: 5 })}
    }
    

    点击Text组件或者Radio组件都会调用onStartRemoteAbility()方法拉起远端FA,onStartRemoteAbility()代码如下:

    function onStartRemoteAbility(deviceId,imageIndexForPosition,pictureList: string[]) {AuthDevice(deviceId);let numDevices = remoteDeviceModel.deviceList.length;if (numDevices === 0) {prompt.showToast({message: "onStartRemoteAbility no device found"});return;}var params = {imageIndexForPosition: JSON.stringify(imageIndexForPosition),pictureList : JSON.stringify(pictureList),remoteDeviceId : localDeviceId}var wantValue = {bundleName: 'com.huawei.cookbook',abilityName: 'com.example.openharmonypicturegame.MainAbility',deviceId: deviceId,parameters: params};featureAbility.startAbility({want: wantValue}).then((data) => {// 拉起远端后,连接远端serviceonConnectRemoteService(deviceId)});
    }
    
  2. 调用featureAbility.connectAbility方法,连接远端Service服务,连接成功后返回remote对象。

    在featureAbility.startAbility()成功的回调中调用onConnectRemoteService()方法,onConnectRemoteService()方法代码如下:

    // 连接远端Service
    async function onConnectRemoteService(deviceId) {// 连接成功的回调async function onConnectCallback(element, remote) {mRemote = remote;}// Service异常死亡的回调function onDisconnectCallback(element) {}// 连接失败的回调function onFailedCallback(code) {prompt.showToast({message: "onConnectRemoteService onFailed: " + code});}let numDevices = remoteDeviceModel.deviceList.length;if (numDevices === 0) {prompt.showToast({message: "onConnectRemoteService no device found"});return;}connectedAbility = await featureAbility.connectAbility({deviceId: deviceId,bundleName: "com.huawei.cookbook",abilityName: "com.example.openharmonypicturegame.ServiceAbility",},{onConnect: onConnectCallback,onDisconnect: onDisconnectCallback,onFailed: onFailedCallback,},);
    }
    

    在配置文件config.json需要设置ServiceAbility的属性visible为true,代码如下:

    "abilities": [...{"visible": true,"srcPath": "ServiceAbility","name": ".ServiceAbility","icon": "$media:icon","srcLanguage": "ets","description": "$string:description_serviceability","type": "service"}
    ],
    

    同时,Service侧也需要在onConnect()时返回IRemoteObject,从而定义与Service进行通信的接口。onConnect()需要返回一个IRemoteObject对象,OpenHarmony提供了IRemoteObject的默认实现,通过继承rpc.RemoteObject来创建自定义的实现类。

    Service侧把自身的实例返回给调用侧的代码如下:

    import rpc from "@ohos.rpc";
    import commonEvent from '@ohos.commonEvent';
    class FirstServiceAbilityStub extends rpc.RemoteObject{constructor(des) {if (typeof des === 'string') {super(des);} else {return null;}}onRemoteRequest(code, data, reply, option) {if (code === 1) {let arr = data.readIntArray();reply.writeInt(100);// 发布公共事件相关流程...} else {}return true;}
    }export default {// 创建Service的时候调用,用于Service的初始化onStart() {},// 在Service销毁时调用。Service应通过实现此方法来清理任何资源,如关闭线程、注册的侦听器等。onStop() {},// 在Ability和Service连接时调用,该方法返回IRemoteObject对象,开发者可以在该回调函数中生成对应Service的IPC通信通道onConnect(want) {try {let value = JSON.stringify(want);} catch(error) {}return new FirstServiceAbilityStub("[pictureGame] first ts service stub");},// 在Ability与绑定的Service断开连接时调用onDisconnect(want) {let value = JSON.stringify(want);},// 在Service创建完成之后调用,该方法在客户端每次启动该Service时都会调用onCommand(want, startId) {let value = JSON.stringify(want);}
    };
    

RPC跨设备通讯

在本章节中,您将学会在成功连接远端Service服务的前提下,如何利用RPC进行跨设备通讯。

  1. 成功连接远端Service服务的前提下,在正文部分增删文字,都会完成一次跨设备通讯,假如在设备A端输入文字,消息的传递是由设备A端的FA传递到设备B的Service服务,发送消息的方法sendMessageToRemoteService()代码如下:

    // 连接成功后发送消息
    async function sendMessageToRemoteService(imageIndexForPosition) {if (mRemote == null) {prompt.showToast({message: "mRemote is null"});return;}let option = new rpc.MessageOption();let data = new rpc.MessageParcel();let reply = new rpc.MessageParcel();data.writeIntArray(JSON.parse(imageIndexForPosition));await mRemote.sendRequest(1, data, reply, option);let msg = reply.readInt();
    }
    
  2. 在B端的Service接收消息,当A端成功连接B端Service服务后,在A端会返回一个remote对象,当A端remote对象调用sendRequest()方法后,在B端的Service中的onRemoteRequest()方法中会接收到发送的消息,其中继承rpc.RemoteObject的类和onRemoteRequest()方法代码如下:

    class FirstServiceAbilityStub extends rpc.RemoteObject{constructor(des) {if (typeof des === 'string') {super(des);} else {return null;}}onRemoteRequest(code, data, reply, option) {if (code === 1) {// 从data中接收数据let arr = data.readIntArray();// 回复接收成功标识reply.writeInt(100);// 发布公共事件相关流程...} else {}return true;}
    }
    

FA订阅公共事件

在九宫格组件PictureGrid的生命周期函数aboutToAppear()中,调用订阅公共事件方法subscribeEvent(),用来订阅"publish_moveImage"公共事件,subscribeEvent()代码如下:

 subscribeEvent(){let self = this;// 用于保存创建成功的订阅者对象,后续使用其完成订阅及退订的动作var subscriber; // 订阅者信息var subscribeInfo = {events: ["publish_moveImage"],priority: 100};// 设置有序公共事件的结果代码回调function SetCodeCallBack(err) {}// 设置有序公共事件的结果数据回调function SetDataCallBack(err) {}// 完成本次有序公共事件处理回调function FinishCommonEventCallBack(err) {}// 订阅公共事件回调function SubscribeCallBack(err, data) {let msgData = data.data;let code = data.code;// 设置有序公共事件的结果代码subscriber.setCode(code, SetCodeCallBack);// 设置有序公共事件的结果数据subscriber.setData(msgData, SetDataCallBack);// 完成本次有序公共事件处理subscriber.finishCommonEvent(FinishCommonEventCallBack)// 处理接收到的数据dataself.imageIndexForPosition = data.parameters.imageIndexForPosition;self.pictureList = [];self.imageIndexForPosition.forEach(value => {if (value == 9) {self.pictureList.push("--")} else {self.pictureList.push(`picture_0` + value + `.png`)}});self.onFinish();}// 创建订阅者回调function CreateSubscriberCallBack(err, data) {subscriber = data;// 订阅公共事件commonEvent.subscribe(subscriber, SubscribeCallBack);}// 创建订阅者commonEvent.createSubscriber(subscribeInfo, CreateSubscriberCallBack);}

在FA中订阅到Service服务发布的"publish_moveImage"事件后,在SubscribeCallBack()回调中重新赋值imageIndexForPosition数组与pictureList数组,从而同步更新界面UI。

service发布公共事件

当Service服务接收到消息后,在onRemoteRequest()发布公共事件,代码如下:

onRemoteRequest(code, data, reply, option) {if (code === 1) {// 从data中接收数据let arr = data.readIntArray();// 回复接收成功标识reply.writeInt(100);// 公共事件相关信息var params ={imageIndexForPosition: arr}var options = {// 公共事件的初始代码code: 1,// 公共事件的初始数据			data: 'init data',、// 有序公共事件 	        isOrdered: true, 	bundleName: 'com.huawei.cookbook',parameters: params}// 发布公共事件回调function PublishCallBack() {}// 发布公共事件commonEvent.publish("publish_moveImage", options, PublishCallBack);} else {}return true;}

在接收到消息后,把接收到的图片位置数组放入params中,然后发布名称为"publish_moveImage"的有序公共事件。

相关文章:

HarmonyOS开发实例:【分布式邮件】

概述 基于TS扩展的声明式开发范式编程语言编写的一个分布式邮件系统,可以由一台设备拉起另一台设备,每次改动邮件内容,都会同步更新两台设备的信息。效果图如下: 搭建OpenHarmony开发环境 完成本篇Codelab我们首先要完成开发环境…...

llama2.c与chinese-baby-llama2语言模型本地部署推理

文章目录 简介Github文档克隆源码英文模型编译运行中文模型(280M)main函数 简介 llama2.c是一个极简的Llama 2 LLM全栈工具,使用一个简单的 700 行 C 文件 ( run.c ) 对其进行推理。llama2.c涉及LLM微调、模型构建、推理端末部署&#xff08…...

008、Python+fastapi,第一个后台管理项目走向第8步:ubutun 20.04下安装vscode+python环境配置

一、说明 白飘了3个月无影云电脑,开始选了个windows server 非常不好用,后台改为ubuntu想升级到22,没成功,那就20.04吧。 今天先安装下开发环境,后续2个月就想把他当做开发服务器,不知道行不行,…...

2024.4.16 驱动开发

思维导图...

如何在 Ubuntu 14.04 上更改 PHP 设置

简介 PHP 是一种服务器端脚本语言,被许多流行的 CMS 和博客平台如 WordPress 和 Drupal 所使用。它也是流行的 LAMP 和 LEMP 堆栈的一部分。更新 PHP 配置设置是设置基于 PHP 的网站时的常见任务。定位确切的 PHP 配置文件可能并不容易。通常在服务器上会有多个 PH…...

【光伏企业】光伏项目怎么做才能提高效率?

一、精细化项目管理 项目规划:在项目启动前,进行充分的调研和规划,明确项目的目标、规模、预算和时间表,确保各项资源得到合理分配。 团队建设:组建一支高效、专业的项目团队,确保团队成员具备光伏领域的…...

毕设选51还是stm32?51太简单?

如果你更倾向于挑战和深入学习,STM32可能是更好的选择。如果你希望更专注于底层硬件原理,51可能更适合。我这里有一套嵌入式入门教程,不仅包含了详细的视频讲解,项目实战。如果你渴望学习嵌入式,不妨点个关注&#xff…...

ip addr和ifconfig区别

ip addr和ifconfig都是用于配置和管理网络接口的工具 1. ifconfig ifconfig是较旧的网络配置工具,属于net-tools套件的一部分。 该命令主要用于配置、显示和控制网络接口的参数,如IP地址、子网掩码、广播地址等。 ifconfig命令的功能相对有限&#xff…...

Springboot+Vue项目-基于Java+MySQL的房产销售系统(附源码+演示视频+LW)

大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:Java毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计 &…...

向量数据库中的向量是什么?

在向量数据库中,向量通常指的是高维空间中的点或方向,它们由一组数值组成,这些数值表示该点在空间中的位置或方向。在机器学习和人工智能领域,向量经常用于表示各种类型的数据,如文本、图像、音频等。 具体来说&#x…...

【重回王座】ChatGPT发布最新模型gpt-4-turbo-2024-04-09

今天,新版GPT-4 Turbo再次在大型模型排行榜上荣登榜首,成功超越了此前领先的Claude 3 Opus。另外,新模型在处理长达64k的上下文时,性能竟能够与旧版在处理26k上下文时的表现相当。 目前GPT-4 Turbo仅限于ChatGPT Plus的用户&…...

NL2SQL基础系列(1):业界顶尖排行榜、权威测评数据集及LLM大模型(Spider vs BIRD)全面对比优劣分析[Text2SQL、Text2DSL]

NL2SQL基础系列(1):业界顶尖排行榜、权威测评数据集及LLM大模型(Spider vs BIRD)全面对比优劣分析[Text2SQL、Text2DSL] Text-to-SQL(或者Text2SQL),顾名思义就是把文本转化为SQL语言,更学术一…...

深度学习基础——计算量、参数量和推理时间

深度学习基础——计算量、参数量和推理时间 在深度学习中,计算量、参数量和推理时间是评估模型性能和效率的重要指标。本文将介绍这三个指标的定义、计算方法以及如何使用Python进行实现和可视化展示,以帮助读者更好地理解和评估深度学习模型。 1. 定义…...

另一棵树的子树

目录 题目 思路 代码1 :相同的树 代码二:解题 注意点 题目 给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。 二叉树 tr…...

【hive】单节点搭建hadoop和hive

一、背景 需要使用hive远程debug,尝试使用无hadoop部署hive方式一直失败,无果,还是使用有hadoop方式。最终查看linux内存占用6GB,还在后台运行docker的mysql(bitnami/mysql:8.0),基本满意。 版本选择: &a…...

Aurora 协议学习理解与应用——Aurora 8B10B协议学习

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 Aurora 8B10B协议学习之一,理解协议 概述8B10B数据发送和接收Symbol-Pairs传输调度用户PDU传输过程用户PDU接收过程 流控自然流量控制操作自然流量控制延迟自然流…...

Vue基础使用之V-Model绑定单选、复选、动态渲染选项的值

这里要说明一下&#xff0c;在v-model 绑定的值是id还是value是和<option>中的v-bind保持一致的&#xff0c;如第四个&#xff0c;如果是 <option :value"op[1]" 那v-model绑定的就是数组第二项的值2&#xff0c;4&#xff0c;6 如果是 <option :va…...

分析ARP解析过程

1、实验环境 主机A和主机B连接到交换机&#xff0c;并与一台路由器互连&#xff0c;如图7.17所示&#xff0c;路由器充当网关。 图7.17 实验案例一示意图 2、需求描述 查看 ARP 相关信息,熟悉在PC 和 Cisco 设备上的常用命令,设置主机A和主机B为同一个网段网关设置为路由接…...

为硬刚小米SU7,华为智界S7整出了「梅开二度」操作

如今国产中大型新能源轿车市场&#xff0c;在小米 SU7 加入后&#xff0c;可算彻底活了过来。 过去几年&#xff0c;咱们自主新能源品牌在 20-30 万元级轿车上发力明显不足&#xff0c;老牌车厂比亚迪汉几乎以一己之力扛起销量担当。 随着新能源汽车消费升级、竞争加剧&#x…...

408数据结构,怎么练习算法大题?

其实考研的数据结构算法题是有得分技巧的 得分要点 会写结构定义&#xff08;没有就自己写上&#xff09;写清楚解题的算法思想描述清楚算法实现最后写出时间和空间复杂度 以上这四步是完成一道算法题的基本步骤&#xff0c;也是其中得分的主要地方就是后面两步。但是前面两…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...