HarmonyOS开发实例:【分布式新闻客户端】

 

介绍

本篇Codelab基于栅格布局、设备管理和多端协同,实现一次开发,多端部署的分布式新闻客户端页面。主要包含以下功能:

  1. 展示新闻列表以及左右滑动切换新闻Tab。
  2. 点击新闻展示新闻详情页。
  3. 点击新闻详情页底部的分享按钮,发现周边处在同一无线网络下的设备并进行可信认证连接。
  4. 可信认证后,再次点击分享按钮,选择已连接的设备进行跨设备启动UIAbility。

最终效果图如下:

相关概念

  • [栅格布局]:一种通用的辅助定位工具,解决多尺寸多设备的动态布局问题。
  • [设备管理]:模块提供分布式设备管理能力。
  • [跨设备启动UIAbility]:多端上的不同UIAbility/ServiceExtensionAbility同时运行、或者交替运行实现完整的业务。
  • [Tabs组件]:通过页签进行内容视图切换的容器组件,每个页签对应一个内容视图。

相关权限

本篇Codelab使用了设备管理及跨设备实现多端协同能力,需要手动替换full-SDK,并在配置文件module.json5文件requestPermissions属性中添加如下权限:

  • [分布式设备认证组网权限]:ohos.permission.ACCESS_SERVICE_DM。
  • [设备间的数据交换权限]:ohos.permission.DISTRIBUTED_DATASYNC。

约束与限制

  1. 本篇Codelab部分能力依赖于系统API,需下载full-SDK并替换DevEco Studio自动下载的public-SDK。具体操作可参考指南[《如何替换full-SDK》]。
  2. 本篇Codelab使用的部分API仅系统应用可用,需要提升应用等级。

环境搭建

软件要求

  • [DevEco Studio]版本:DevEco Studio 4.0 Beta2。
  • OpenHarmony SDK版本:API version 10。
  • 鸿蒙开发文档指导:qr23.cn/AKFP8k点击或复制转到。

硬件要求

  • 开发板类型:[润和RK3568开发板]。
  • OpenHarmony系统:4.0 Beta1。 -鸿蒙HarmonyOS与OpenHarmony开发籽料mau123789是v直接拿

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

环境搭建

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

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

  1. 搭建烧录环境。

    1. [完成DevEco Device Tool的安装]
    2. [完成RK3568开发板的烧录]
  2. 搭建开发环境。

    1. 开始前请参考[工具准备],完成DevEco Studio的安装和开发环境配置。
    2. 开发环境配置完成后,请参考[使用工程向导]创建工程(模板选择“Empty Ability”)。
    3. 工程创建完成后,选择使用[真机进行调测]。

代码结构解读

本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。

├──entry/src/main/ets                   // 代码区
│  ├──common
│  │  ├──constants
│  │  │  └──CommonConstants.ets         // 常量类
│  │  └──utils
│  │     └──Logger.ets                  // 日志工具类
│  ├──entryability
│  │  └──EntryAbility.ets               // 程序入口类
│  ├──model
│  │  └──RemoteDeviceModel.ets          // 设备管理类
│  ├──pages
│  │  ├──Index.ets                      // 新闻列表页
│  │  └──NewsDetail.ets                 // 新闻详情页
│  ├──view
│  │  ├──DetailFooter.ets               // 详情页页脚
│  │  ├──DetailHeadContent.ets          // 新闻详情
│  │  ├──DeviceListDialog.ets           // 设备列表弹窗
│  │  ├──NewsList.ets                   // 新闻列表
│  │  └──NewsTab.ets                    // 新闻页签
│  └──viewmodel
│     └──NewsDataModel.ets              // 新闻数据处理
└──entry/src/main/resources             // 资源文件目录

构建新闻列表页

新闻列表页由页签区域和新闻列表区域组成,页签区域为自定义布局TabBuilder,新闻列表区域为Tabs组件嵌套List组件,并适配不同尺寸设备对应的栅格。新闻列表页能够左右滑动或点击页签切换新闻Tab,并设置点击新闻跳转至新闻详情页。

 
// NewsTab.ets
@Component
export default struct NewsTab {@State currentIndex: number = 0;@State currentBreakpoint: string = CommonConstants.BREAKPOINT_SM;private newsItems: NewsData[] = [];// 自定义页签栏@Builder TabBuilder(title: Resource, index: number) {Row() {Text(title).fontSize(this.currentIndex === index ? $r('app.float.lager_font_size') : $r('app.float.middle_font_size')).fontWeight(this.currentIndex === index ? CommonConstants.FONT_WEIGHT_500 : FontWeight.Normal).fontColor(this.currentIndex === index ? $r('app.color.tab_font_select') : $r('app.color.font_color_gray'))}.layoutWeight(1).margin({right: $r('app.float.news_tab_margin_right'),left: (this.currentBreakpoint === CommonConstants.BREAKPOINT_SM && index === 0) ?$r('app.float.news_tab_margin_left') : 0}).height(this.currentIndex === index ? $r('app.float.news_tab_current_height') : $r('app.float.news_tab_height'))}build() {...Tabs() {ForEach(CommonConstants.ALL_TITLE, (title: string, index: number) => {TabContent() {// 新闻内容列表NewsList({ newsItems: NewsDataModel.getNewsByType(this.newsItems, title) })}.tabBar(this.TabBuilder(NewsDataModel.getTypeByStr(title), index))}, (title: string, index: number) => index + JSON.stringify(title))}.barHeight($r('app.float.news_tab_bar_height')).barWidth(CommonConstants.FULL_COMPONENT).barMode(this.currentBreakpoint === CommonConstants.BREAKPOINT_SM ? BarMode.Scrollable : BarMode.Fixed).onChange((index: number) => {this.currentIndex = index;})...}
}// NewsList.ets
@Component
export default struct NewsList {private newsItems: NewsData[] = [];build() {List() {ForEach(this.newsItems, (item: NewsData, index: number) => {ListItem() {// 栅格布局GridRow({columns: {sm: CommonConstants.FOUR_COLUMN,md: CommonConstants.EIGHT_COLUMN,lg: CommonConstants.TWELVE_COLUMN},breakpoints: {value: [CommonConstants.SMALL_DEVICE_TYPE,CommonConstants.MIDDLE_DEVICE_TYPE,CommonConstants.LARGE_DEVICE_TYPE]},gutter: { x: $r('app.float.grid_row_gutter') }}) {GridCol({span: {sm: CommonConstants.FOUR_COLUMN,md: CommonConstants.EIGHT_COLUMN,lg: CommonConstants.EIGHT_COLUMN},offset: {sm: CommonConstants.ZERO_COLUMN,md: CommonConstants.ZERO_COLUMN,lg: CommonConstants.TWO_COLUMN}}) {NewsItem({ newsItem: item, isLast: index === this.newsItems.length - 1 })}}}}, (item: NewsData, index: number) => index + JSON.stringify(item))}.height(CommonConstants.FULL_COMPONENT)}
}

构建新闻详情页

新闻详情页

新闻详情页由新闻内容区域和页脚区域组成,其中新闻内容区域为Scroll组件嵌套栅格组件展示新闻详情,页脚区域为栅格布局,包含TextInput组件和三个按钮图标。

 
// DetailHeadContent.ets
build() {Column() {...// 可滚动的容器组件Scroll() {// 栅格布局GridRow({columns: {sm: CommonConstants.FOUR_COLUMN,md: CommonConstants.EIGHT_COLUMN,lg: CommonConstants.TWELVE_COLUMN},breakpoints: {value: [CommonConstants.SMALL_DEVICE_TYPE,CommonConstants.MIDDLE_DEVICE_TYPE,CommonConstants.LARGE_DEVICE_TYPE]},gutter: { x: $r('app.float.grid_row_gutter') }}) {GridCol({span: {sm: CommonConstants.FOUR_COLUMN,md: CommonConstants.EIGHT_COLUMN,lg: CommonConstants.EIGHT_COLUMN},offset: {sm: CommonConstants.ZERO_COLUMN,md: CommonConstants.ZERO_COLUMN,lg: CommonConstants.TWO_COLUMN}}) {...}...}}.padding({bottom: $r('app.float.news_detail_padding_bottom')}).scrollBar(BarState.Off)}.margin({left: $r('app.float.news_detail_margin'),right: $r('app.float.news_detail_margin')}).height(CommonConstants.FULL_COMPONENT).alignItems(HorizontalAlign.Start)
}// DetailFooter.ets
build() {Column() {// 分割线Divider().color($r('app.color.detail_divider_color')).width(CommonConstants.FULL_COMPONENT)// 栅格布局GridRow({columns: {sm: CommonConstants.FOUR_COLUMN,md: CommonConstants.EIGHT_COLUMN,lg: CommonConstants.TWELVE_COLUMN},breakpoints: {value: [CommonConstants.SMALL_DEVICE_TYPE,CommonConstants.MIDDLE_DEVICE_TYPE,CommonConstants.LARGE_DEVICE_TYPE]},gutter: { x: $r('app.float.grid_row_gutter') }}) {GridCol({span: {sm: CommonConstants.FOUR_COLUMN,md: CommonConstants.EIGHT_COLUMN,lg: CommonConstants.EIGHT_COLUMN},offset: {sm: CommonConstants.ZERO_COLUMN,md: CommonConstants.ZERO_COLUMN,lg: CommonConstants.TWO_COLUMN}}) {...}.margin({left: this.currentBreakpoint === CommonConstants.BREAKPOINT_SM ? $r('app.float.footer_margin_sm') :$r('app.float.footer_margin_other'),right: this.currentBreakpoint === CommonConstants.BREAKPOINT_SM ? $r('app.float.footer_margin_sm') :$r('app.float.footer_margin_other')})}.backgroundColor($r('app.color.bg_color_gray')).height($r('app.float.footer_height')).width(CommonConstants.FULL_COMPONENT).onBreakpointChange((breakpoints) => {...})}
}

分享按钮弹窗

页脚点击分享按钮,弹出自定义弹窗DeviceListDialog,用于多端协同拉起应用。DeviceListDialog由两个标题栏和两个List组件构成,其中List组件使用ForEach循环渲染设备数据。

 
// DeviceListDialog.ets
build() {Column() {Row() {...}.height($r('app.float.choose_device_row_height')).width(CommonConstants.FULL_COMPONENT).padding({left: $r('app.float.dialog_padding'),right: $r('app.float.dialog_padding')})// 信任设备列表List() {ForEach(this.trustedDeviceList, (item: deviceManager.DeviceInfo, index: number) => {ListItem() {...}}, (item: deviceManager.DeviceInfo) => JSON.stringify(item.deviceId))}Row() {...}.height($r('app.float.choose_device_row_height')).width(CommonConstants.FULL_COMPONENT).padding({left: $r('app.float.dialog_padding'),right: $r('app.float.dialog_padding')})// 发现设备列表List() {ForEach(this.discoverDeviceList, (item: deviceManager.DeviceInfo, index: number) => {ListItem() {...}}, (item: deviceManager.DeviceInfo) => JSON.stringify(item.deviceId))}Row() {...}.height($r('app.float.dialog_button_row_height')).padding({top: $r('app.float.dialog_button_padding_top'),bottom: $r('app.float.dialog_button_padding_bottom'),left: $r('app.float.dialog_padding'),right: $r('app.float.dialog_padding')}).width(CommonConstants.FULL_COMPONENT)}.borderRadius($r('app.float.dialog_border_radius')).backgroundColor($r('app.color.device_dialog_background')).width(CommonConstants.FULL_COMPONENT)
}

多端协同拉起应用

创建设备管理器

应用创建时创建一个设备管理器实例,注册设备状态监听和获取信任的设备列表。其中deviceManager类需使用full-SDK。

// EntryAbility.ets
onCreate(want: Want) {...// 创建设备管理器RemoteDeviceModel.createDeviceManager(this.context);
}// RemoteDeviceModel.ets
async createDeviceManager(context: common.UIAbilityContext): Promise<void> {if (this.deviceManager !== undefined) {return;}await new Promise((resolve: (value: Object | PromiseLike<Object>) => void, reject:((reason?: RejectError) => void)) => {deviceManager.createDeviceManager(context.abilityInfo.bundleName, (err, value) => {if (err) {reject(err);logger.error('createDeviceManager failed.');return;}this.deviceManager = value;// 注册设备状态监听this.registerDeviceStateListener();// 获取信任设备列表this.getTrustedDeviceList();resolve(value);})})
}

发现设备

用户点击新闻详情页底部的分享按钮,调用startDeviceDiscovery()方法,发现周边处在同一无线网络下的设备并添加设备至已发现的设备列表。

// RemoteDeviceModel.ets
startDeviceDiscovery(): void {if (this.deviceManager === undefined) {logger.error('deviceManager has not initialized');this.showToast($r('app.string.no_device_manager'));return;}this.deviceManager.on('deviceFound', (data) => {if (data === null) {return;}// 监听设备发现this.deviceFound(data);})this.deviceManager.on('discoverFail', (data) => {logger.error(`discoverFail data = ${JSON.stringify(data)}`);})this.deviceManager.on('serviceDie', () => {logger.error('serviceDie');})let info: deviceManager.SubscribeInfo = {subscribeId: SUBSCRIBE_ID,mode: CommonConstants.INFO_MODE,medium: 0,freq: CommonConstants.INFO_FREQ,isSameAccount: false,isWakeRemote: true,capability: 0};// 添加设备至发现列表this.discoverList = [];AppStorage.setOrCreate(CommonConstants.DISCOVER_DEVICE_LIST, this.discoverList);try {this.deviceManager.startDeviceDiscovery(info);} catch (err) {logger.error(`startDeviceDiscovery failed error = ${JSON.stringify(err)}`);}
}

进行可信认证连接

在已发现的设备列表中选择设备,调用authenticateDevice()方法进行可信认证,输入PIN码,连接设备,将设备改为信任状态,添加至已信任设备列表。

// RemoteDeviceModel.ets
authenticateDevice(device: deviceManager.DeviceInfo, context: common.UIAbilityContext): void {if (this.deviceManager === undefined) {logger.error('deviceManager has not initialized');this.showToast($r('app.string.no_device_manager'));return;}for (let i: number = 0; i < this.discoverList.length; i++) {if (this.discoverList[i].deviceId !== device.deviceId) {continue;}let extraInfo: AuthExtraInfoInterface = {targetPkgName: context.abilityInfo.bundleName,appName: context.applicationInfo.name,appDescription: context.applicationInfo.description,business: CommonConstants.ZERO};let authParam: deviceManager.AuthParam = {'authType': CommonConstants.ONE,'extraInfo': extraInfo};try {// 可信认证this.deviceManager.authenticateDevice(device, authParam, (err) => {if (err) {logger.error(`authenticateDevice error. Code is ${err.code}, message is ${err.message}`);return;}})} catch (err) {logger.error(`authenticateDevice failed error = ${JSON.stringify(err)}`);}}
}

跨设备启动UIAbility

可信认证后,用户再次点击分享按钮,选择已信任设备列表中的设备,调用startAbilityContinuation()方法进行拉起应用,在另一设备中触发aboutToAppear()方法渲染当前的新闻详情页,实现跨设备启动UIAbility。

// DeviceListDialog.ets
function startAbilityContinuation(deviceId: string, newsId: string, context: common.UIAbilityContext): void {let want: Want = {deviceId: deviceId,bundleName: context.abilityInfo.bundleName,abilityName: CommonConstants.ABILITY_NAME,parameters: {newsId: newsId}};// 拉起应用context.startAbility(want).catch((err: Error) => {Logger.error(`startAbilityContinuation failed error = ${JSON.stringify(err)}`);prompt.showToast({message: $r('app.string.start_ability_continuation_error')});})
}// NewsDetail.ets
aboutToAppear() {let newsId: string | undefined = AppStorage.get<string>('wantNewsId');if (newsId === undefined) {this.newsData = (router.getParams() as Record<string, NewsData>)['newsItem'];return;}// 读取跨设备传递的参数信息this.newsData = this.newsItems.filter((item: NewsData) => (item.newsId === newsId))[0];
}

最后呢,很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。

而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点

如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。

高清完整版请点击→《鸿蒙NEXT星河版开发学习文档》

针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细资料鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,帮助大家在技术的道路上更进一步。

《鸿蒙 (OpenHarmony)开发学习视频》

图片

《鸿蒙生态应用开发V2.0白皮书》

图片

《鸿蒙 (OpenHarmony)开发基础到实战手册》

获取这份鸿蒙星河版学习资料,请点击→《鸿蒙NEXT星河版开发学习文档》

OpenHarmony北向、南向开发环境搭建

图片

《鸿蒙开发基础》

  1. ArkTS语言

  2. 安装DevEco Studio

  3. 运用你的第一个ArkTS应用

  4. ArkUI声明式UI开发

  5. .……

图片

《鸿蒙开发进阶》

  1. Stage模型入门

  2. 网络管理

  3. 数据管理

  4. 电话服务

  5. 分布式应用开发

  6. 通知与窗口管理

  7. 多媒体技术

  8. 安全技能

  9. 任务管理

  10. WebGL

  11. 国际化开发

  12. 应用测试

  13. DFX面向未来设计

  14. 鸿蒙系统移植和裁剪定制

  15. ……

图片

《鸿蒙开发实战》

  1. ArkTS实践

  2. UIAbility应用

  3. 网络案例

  4. ……

图片

 获取这份鸿蒙星河版学习资料,请点击→《鸿蒙NEXT星河版开发学习文档》

总结

鸿蒙—作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发

并且鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用那么这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行!

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

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

相关文章

Elasticsearch:如何将 MongoDB 数据引入 Elastic Cloud

作者&#xff1a;Hemendra Singh Lodhi Elastic Cloud 是由 Elastic 提供的基于云的托管服务。Elastic Cloud 允许客户在亚马逊网络服务 (AWS)、谷歌云平台 (GCP) 和微软 Azure 上部署、管理和扩展他们的 Elasticsearch 集群。 MongoDB 是一种流行的 NoSQL 文档导向数据库&am…

web安全学习笔记(10)

记一下第十四节课的内容。 一、MySQL学习 数据库基本结构&#xff1a;库——表——列——值 在本地打开navicat&#xff0c;连接数据库&#xff0c;新建一个liuyan库、liuyan库下新建一个member表&#xff1a; 在表里随意添加一些数据&#xff1a; 下面我们学习MySQL查询。新…

【Web】NewStarCTF 2022 题解(全)

目录 Week1 HTTP Head?Header! 我真的会谢 NotPHP Word-For-You Week2 Word-For-You(2 Gen) IncludeOne UnserializeOne ezAPI Week3 BabySSTI_One multiSQL IncludeTwo Maybe You Have To think More Week4 So Baby RCE BabySSTI_Two UnserializeT…

C++修炼之路之STL_stack,queue和容器适配器

目录 前言 一&#xff1a;SLT中stack和queue的基本使用 1.在官网中对stack和queue的简单介绍 2.数据结构中栈和队列的基本知识和操作 3. STL中stack的接口函数及使用 4.STL中queue的接口函数及使用 二&#xff1a;容器适配器Container 三&#xff1a;使用容器适配器…

springboot Logback 不同环境,配置不同的日志输出路径

1.背景&#xff1a; mac 笔记本开发&#xff0c;日志文件写到/data/logs/下&#xff0c;控制台报出&#xff1a;Failed to create parent directories for [/data/logs/........... 再去手动在命令窗口创建文件夹data&#xff0c;报Read-only file system 2.修改logback-spri…

Linux安装和使用Android Debug Bridge(ADB)

目录 1、开发环境和工具 2、ADB是什么&#xff1f; 3、安装ADB 3.1、使用包管理器安装 ADB 3.2、手动安装 ADB 4、使用ADB 4.1、连接设备 4.2、执行shell命令 4.3、安装应用程序 4.4、截取屏幕截图 4.5、模拟按键和手势 4.6、上传文件到Android设备 4.7、从Android设备下载文件…

BGP边界网关路由实验(华为)

一&#xff0c;技术简介 BGP&#xff08;边界网关路由协议&#xff09;是一种自治系统&#xff08;AS&#xff09;间的协议&#xff0c;主要用于在不同的AS之间交换路由信息。AS是一个由一组网络设备和路由器组成的网络集合&#xff0c;这些设备可以在一个共同的管理域中协同工…

1 回归:锂电池温度预测top2 代码部分(一) Tabnet

2024 iFLYTEK A.I.开发者大赛-讯飞开放平台 TabNet&#xff1a; 模型也是我在这个比赛一个意外收获&#xff0c;这个模型在比赛之中可用。但是需要GPU资源&#xff0c;否则运行真的是太慢了。后面针对这个模型我会写出如何使用的方法策略。 比赛结束后有与其他两位选手聊天&am…

win2022服务器apache配置https(ssl)真实环境实验(避坑之作)不依赖宝塔小皮等集成环境

本次实验背景&#xff1a; 完全参考官方 https://cloud.tencent.com/document/product/400/4143 文档流程&#xff0c;没有搞定&#xff0c;于是写下避坑之作。 服务器&#xff1a;腾讯云轻量应用服务器 操作系统&#xff1a; Windows Server 2022 DataCenter 64bit CN apache…

李沐45_SSD实现——自学笔记

主体思路&#xff1a; 1.生成一堆锚框 2.根据真实标签为每个锚框打标(类别、偏移、mask) 3.模型为每个锚框做一个预测(类别、偏移) 4.计算上述二者的差异损失&#xff0c;以更新模型weights 先读取一张图像。 它的高度和宽度分别为561和728像素。 %matplotlib inline import …

Photoshop 2024 (ps) v25.6中文 强大的图像处理软件 mac/win

Photoshop 2024 for Mac是一款强大的图像处理软件&#xff0c;专为Mac用户设计。它继承了Adobe Photoshop一贯的优秀功能&#xff0c;并进一步提升了性能和稳定性。 Mac版Photoshop 2024 (ps)v25.6中文激活版下载 win版Photoshop 2024 (ps)v25.6直装版下载 无论是专业的设计师还…

EI Scopus双检索 | 2024年清洁能源与智能电网国际会议(CCESG 2024)

会议简介 Brief Introduction 2024年清洁能源与智能电网国际会议(CCESG 2024) 会议时间&#xff1a;2024年 11月27-29日 召开地点&#xff1a;澳大利亚悉尼 大会官网&#xff1a;CCESG 2024-2024 International Joint Conference on Clean Energy and Smart Grid 由CoreShare科…

m4p转换mp3格式怎么转?3个Mac端应用~

M4P文件格式的诞生伴随着苹果公司引入FairPlay版权管理系统&#xff0c;该系统旨在保护音频的内容。M4P因此而生&#xff0c;成为受到FairPlay系统保护的音频格式&#xff0c;常见于苹果设备的iTunes等平台。 MP3文件格式的多个优点 MP3格式的优点显而易见。首先&#xff0c;其…

k8s之etcd

1.特点&#xff1a; etcd 是云原生架构中重要的基础组件。有如下特点&#xff1a; 简单&#xff1a;安装配置简单&#xff0c;而且提供了 HTTP API 进行交互&#xff0c;使用也很简单键值对存储&#xff1a;将数据存储在分层组织的目录中&#xff0c;如同在标准文件系统中监…

vscode msvc qt环境搭建

自己整了好久都没把环境搞好&#xff0c;后来发现已经有大佬搞好了插件&#xff0c;完全不需要自己整理。 下载如下插件&#xff1a; 第二个qt插件就可以自动帮我们生成工程了。 可惜目前似乎支持win&#xff0c;另外就是debug模式运行后会报qwindowsd.dll插件找不到的错误&a…

【简单讲解下如何用爬虫玩转石墨文档】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

链表OJ - 6(链表分割)

题目描述&#xff08;来源&#xff09; 现有一链表的头指针 ListNode* pHead&#xff0c;给一定值x&#xff0c;编写一段代码将所有小于x的结点排在其余结点之前&#xff0c;且不能改变原来的数据顺序&#xff0c;返回重新排列后的链表的头指针。 思路 创建两个链表&#xff0c…

ChatGPT:引领未来的语言模型革命?

一、引言 随着人工智能技术的不断发展&#xff0c;Chat GPT作为一种自然语言处理技术&#xff0c;已经逐渐渗透到各个领域&#xff0c;具有广泛的应用前景。本文将从多个角度探讨Chat GPT的应用领域及其未来发展趋势。 ChatGPT的语言处理能力超越了以往任何一款人工智能产品。…

Docker一键快速私有化部署(Ollama+Openwebui) +AI大模型(gemma,llama2,qwen)20240417更新

几行命令教你私有化部署自己的AI大模型&#xff0c;每个人都可以有自己的GTP 第一步&#xff1a;安装Docker(如果已经有了可以直接跳第二步) ####下载安装Docker wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O/etc/yum.repos.d/docker-ce.repo##…

STM32 USB虚拟串口

电路原理图 usb部分 晶振部分 usb与单片机连接 配置信息 sys配置信息 rcc配置信息 usb配置信息 虚拟串口配置信息 时钟配置信息 项目配置信息 代码 包含文件 主函数代码 实验效果 修改接收波特率依然可以正常接收&#xff0c;也就是说单片机可以自动适应上位机的波特率设置。…