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

鸿蒙跨平台框架ArkUI-X

01

引言

目前,移动端主流跨平台方案有Flutter、React Native、uni-app等等,还有刚推出不久的Compose-Multiplatform,真所谓是百花齐放。这些框架各有特点,技术实现各有差异,比如Flutter通过Dart编写的UI描述对接Flutter渲染引擎,React Native 则是借助大前端成熟的发展背景,利用JS引擎生成UI描述,渲染时转化为原生控件,复用了原生渲染能力。至于选择哪种框架实现跨平台取决于项目的具体需求、开发团队的技能和偏好。今天我们探索一个新的框架——ArkUI-X。

02

ArkTS、ArkUI、ArkUI-X

在探索ArkUI-X之前,先了解一下ArkTS、ArkUI、ArkUI-X三者关系:

  • ArkTS 是华为基于TypeScript自研的开发语言,主要用于Harmony应用层开发。ArkTS在保持原 TS 基本语法风格的基础上,对 TS 的动态类型特性施加了更严格的约束,引入静态类型,减少运行时的类型检查,有助于性能提升;

  • ArkUI 是一套声明式UI开发框架。包含一系列UI组件(Text、Image)、状态管理(State、LocalStorage)、界面绘制、交互事件以及实时界面预览工具;

  • ArkUI-X 进一步将 ArkUI 扩展到多个 OS 平台,目前支持 OpenHarmony、HarmonyOS、Android、iOS,后续会逐步增加更多平台支持。

简单来说,开发者基于ArkUI框架,使用ArkTS语言进行编码,构建OpenHarmony/HarmonyOS应用,为了让应用运行到Android iOS上,利用 ArkUI-X 框架实现各OS平台的适配和构建。接下来我们将创建一个 ArkUI-X 简易Demo,通过Demo来探索ArkUI如何绘制组件到屏幕,ArkUI-X如何扩展ArkUI到Android平台,ArkUI-X如何与Android系统能力交互。

03

快速上手

3.1 环境搭建

  1. DevEco Studio

首先从DevEco Studio官方网站(https://developer.huawei.com/consumer/cn/deveco-studio/)下载并安装DevEco Studio,需要选择4.0.0以上版本,以支持 ArkUI-X 套件。然后在DevEco Studio内部,分别下载HarmonyOS SDK 和 ArkUI-X,非合作企业开发者下载OpenHarmony SDK 和 ArkUI-X。

下载OpenHarmony SDK示例:

1.png

下载ArkUI-X示例:2.png

  1. Android Studio

因为最终要打出Android的apk实现跨平台,所以需要安装Android Studio。安装步骤对客户端小伙伴都已经轻车熟路了,强调一点:需要额外配置ANDROID_HOME(Android SDK安装路径)到系统环境变量中,这是步骤一中DevEco Studio编译项目的必备条件之一。

  1. Xcode 同理,使用Xcode导入iOS项目,打IPA格式的安装包。

3.2 创建工程

完成上述的环境搭建后,就可以创建工程了。可以通过 ArkUI-X 基础模板进行创建。 3.png
创建工程

创建完成后,得到这样一个工程结构:

4.png
项目结构
  • entry:存放的是应用程序入口、核心业务逻辑以及资源文件。跨平台的公共源代码放在entry下,这点和纯Harmony项目结构一致;

  • .arkui-x/android:是一个标准的Android项目结构。但目前文件还不完整,需要Build App/Hap之后,才会生成更为完整的Android项目;

  • .arkui-x/iOS: 是一个标准的iOS项目结构,包含project.pbxproj。

Build App/Hap之后,在build目录下生成的后缀名.hap文件,可安装到HarmonyOS平台上。其它平台需要单独打包,.arkui-x下的Android项目导入到Android Studio中打出.apk;.arkui-x下的iOS项目导入到Xcode中打出.IPA。至此完成三个平台的打包工作。也就是说,在Build App过程中,ArkUI-X框架会把entry里公用ArkTS代码和resource,打入到各平台的安装包或项目文件中。

应用调试方面,目前只支持HarmonyOS调试,Android和iOS暂不支持ArkTS调试。

其实上述的环境搭建、新建项目、编译打包和安装调试,还有另一种方式实现——ACE Tools,是一套为ArkUI-X开发者提供的命令行工具。详情参见:ACE Tools快速指南(https://gitee.com/arkui-x/docs/blob/master/zh-cn/application-dev/quick-start/start-with-ace-tools.md)

04

窥探ArkUI的绘制过程

在了解 ArkUI-X 实现跨平台之前,我们先简单过一遍ArkTS编写的UI界面,是如何绘制到OpenHarmony/HarmonyOS上的,以上面的Demo为例:

// Index.ets
@Entry
@Component
struct Index {@State message: string = '今天星期五'build() {Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold)}.width('100%')}.height('100%')}
}

Build App / Hap 之后得到hap包,和Android apk类似,对hap包进行解压得到modules.abc字节码文件 (Ark Byte Code),再对字节码文件进行16进制解析,可以看到这样一段代码:

class Index extends ViewPU {constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) {super(parent, __localStorage, elmtId, extraInfo);this.__message = new ObservedPropertySimplePU('今天星期五', this, "message");this.setInitiallyProvidedValue(params);}setInitiallyProvidedValue(params: Index_Params) {if (params.message !== undefined) {this.message = params.message;}}aboutToBeDeleted() {this.__message.aboutToBeDeleted();SubscriberManager.Get().delete(this.id__());}private __message: ObservedPropertySimplePU<string>;initialRender() {   // 编译器根据ArkTS中对组件的描述部分,重新生成jsthis.observeComponentCreation2((elmtId, isInitialRender) => {Row.create();Row.height('100%');}, Row);this.observeComponentCreation2((elmtId, isInitialRender) => {Column.create();Column.width('100%');}, Column);this.observeComponentCreation2((elmtId, isInitialRender) => {Text.create(this.message);Text.fontSize(50);Text.fontWeight(FontWeight.Bold);}, Text);Text.pop();Column.pop();Row.pop();}
}

可以看出,我们用@Component编写的组件,经过ArkCompiler编译后,会生成一个继承自ViewPU的js类,这个过程和kotlin经过kotlin编译器生成java有点类似。ViewPU位于ArkUI框架的arkui_ace_engine

(https://gitee.com/openharmony/arkui_ace_engine/tree/master)仓, 部分代码如下:

// 位于 frameworks/bridge/declarative_frontend/state_mgmt/src/lib/partial_update/pu_view.ts
abstract class ViewPU extends PUV2ViewBase implements IViewPropertiesChangeSubscriber, IView {constructor(parent: IView, localStorage: LocalStorage, elmtId: number = UINodeRegisterProxy.notRecordingDependencies, extraInfo: ExtraInfo = undefined) {super(parent, elmtId, extraInfo); this.id_ = SubscriberManager.MakeId() : elmtId;if (localStorage) {this.localStorage_ = localStorage;}SubscriberManager.Add(this);}public initialRenderView(): void {this.obtainOwnObservedProperties();this.initialRender();...}// 编译器生成的js类会实现该方法,主要是对组件的描述protected abstract initialRender(): void;// implements IMultiPropertiesChangeSubscriber UI状态变化回调viewPropertyHasChanged(varName: PropertyInfo, dependentElmtIds: Set<number>): void {if (dependentElmtIds.size && !this.isFirstRender()) { // 第一次走initialRenderView()if (!this.dirtDescendantElementIds_.size && !this.runReuse_) {this.markNeedUpdate(); // 更新UI 最终调到C++}...}let cb = this.watchedProps.get(varName);if (cb && typeof cb === 'function') {// ArkTS中@Prop @Watch('xxx') value 的invokecb.call(this, varName);}}
}

从上面ViewPU的部分代码,可以提取几点信息:

  1. 构造方法第一个参数parent: IView,说明整个UI结构中存在子父组件概念,其内部维护一个子父组件关系链,这点和其它UI框架一样;

  2. 构造逻辑依次是:

  • 生成element Id,用于局部刷新;

  • 定义localStorage对象,用于页面状态共享;

  • SubscriberManager.Add(this),添加订阅,监听状态变化。

状态变化后,回调viewPropertyHasChanged,更新UI并执行@Watch装饰器逻辑。

更多实现可查看源码,当然只需要看看流程即可,因为代码的commit频次比较高,每次打开看细节都可能有所变化,而且还存在很多同名v2类、v2方法。总之,ViewPU 是所有组件的基类,ViewPU 继承自 PUV2ViewBasePUV2ViewBase 继承自 NativeViewPartialUpdate。从下面代码块的注释得知,UI渲染将在 C++ 里面实现,将通过NAPINAPIJNI 类似)完成jsC++的交互。

// 位于 frameworks/bridge/declarative_frontend/state_mgmt/src/lib/puv2_common/puv2_view_base.ts 和 puv2_view_native_base.d.ts
// implemented in C++  for release
abstract class PUV2ViewBase extends NativeViewPartialUpdate {...
}/*** NativeViewPartialUpdate aka JSViewPartialUpdate C++ class exposed to JS*  all definitions in this file are framework internal*/
declare class NativeViewPartialUpdate {constructor();markNeedUpdate(): void; // 更新UIfinishUpdateFunc(elmtId: number): void;...static create(newView: NativeViewPartialUpdate): void;
}

markNeedUpdate()主要负责UI刷新,追踪一下它的实现逻辑:

// 位于 frameworks/bridge/declarative_frontend/jsview/js_view.cpp
void JSViewPartialUpdate::JSBind(BindingTarget object)
{JSClass<JSViewPartialUpdate>::Declare("NativeViewPartialUpdate");JSClass<JSViewPartialUpdate>::StaticMethod("create", &JSViewPartialUpdate::Create, opt);JSClass<JSViewPartialUpdate>::Method("markNeedUpdate", &JSViewPartialUpdate::MarkNeedUpdate);
}void JSViewPartialUpdate::MarkNeedUpdate()
{needsUpdate_ = ViewPartialUpdateModel::GetInstance()->MarkNeedUpdate(viewNode_);
}
// 位于 frameworks/bridge/declarative_frontend/jsview/models/view_partial_update_model_impl.cpp
bool ViewPartialUpdateModelImpl::MarkNeedUpdate(const WeakPtr<AceType>& node)
{auto weakElement = AceType::DynamicCast<ComposedElement>(node);auto element = weakElement.Upgrade();if (element) {element->MarkDirty();}return true;
}

ComposedElementpipeline 记录组件信息的对象,weakElement.Upgrade()ComposedElement 放入 pipeline 中,最终通过图形渲染引擎(OpenGL ES、Skia)完成显示。详细代码参考frameworks/core/pipeline/base/composed_element.cpp

05

Android跨平台的实现

以上是一个hap包通过ArkUI完成渲染的大致过程,回到跨平台ArkUI-X,相同的ArkTS代码是如何运行在Android设备上的呢?

打开Android项目,看到assets下存放着ArkCompiler编译产物,和上一节中对.hap包解压后得到的文件一模一样。这是在编译环节中,编译脚本copy一份modules.abc字节码和resource到Android工程下,作为Android应用资源,打包时将以assets形式打入apk。

src/main/assets/arkui-x├── entry|   ├── ets|   |   ├── modules.abc|   |   └── sourceMaps.map|   ├── resouces.index|   ├── resouces|   └── module.json└── systemres

如何在Android上执行modules.abc字节码呢?打开libs,发现ArkUI相关的so动态库和jar包。

libs├── armabi-v7a|   ├── libarkui_android.so|   └── libhilog.so└── arkui_android_adapter.jar

其中libarkui_android.soarkui_ace_enginearkui_napifoundation/appframeworkarkui_for_android... 所编译出的动态库,是运行和界面渲染的必要环境。另一个arkui_android_adapter.jar的功能是:Android Application需要继承arkui_android_adapter.jar包所提供的StageApplicationStageApplication用于初始化资源路径以及加载配置信息。Activity需要继承arkui_android_adapter.jar包所提供的StageActivityStageActivity主要功能是将Android中Activity的生命周期与Harmony中Ability的生命周期进行映射。除此之外,arkui_android_adapter.jar适配了系统平台能力,如粘贴板、软键盘、字体、存储、日志。这里有个疑问:ArkUI-X是如何实现与Android系统之间的交互呢?ArkTSJava没有相互调用的能力,为了实现ArkTSJava交互,需要ArkTSC++交互,C++再与Java交互,调用链为ArkTS  -> NAPI -> C++ -> JNI -> Java,反之亦然,看起来十分复杂。ArkUI-X提供一套桥接能力,对于开发者来说,并不用关心这些封装逻辑,实际开发过程中,就像是ArkTSJava直接交互。

下面通过粘贴板的例子,探究它的具体实现过程。我们给系统粘贴板设置数据——'明天星期六',使用ArkTS实现如下,看看最终是如何调到Android Framework 给粘贴板设置数据的api:ClipboardManager#setPrimaryClip()

import pasteboard from '@ohos.pasteboard';Button('拷贝到粘贴板').onClick(() => {let pasteData: pasteboard.PasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, '明天星期六')let systemPasteboard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard()systemPasteboard.setData(pasteData)})

这段代码对接ArkUI的调用链和上一节中渲染UI类似,就不再赘述了。粘贴板相关api 在 arkui_ace_engine中定义成抽象接口,如下:

// 位于 arkui_ace_engine/frameworks/core/common/clipboard/clipboard.h
namespace OHOS::Ace {class Clipboard : public AceType {DECLARE_ACE_TYPE(Clipboard, AceType);public:~Clipboard() override = default;virtual void SetData(const std::string& data, CopyOptions copyOption = CopyOptions::InApp, bool isDragData = false) = 0;}
}

ArkUI-X 分平台对接口进行不同实现,Android的实现在arkui_for_android仓库中,其定义和实现如下,可见粘贴板设置数据api SetData()最终到ClipboardJni::SetData(data)

// 位于 arkui_for_android/capability/java/jni/clipboard/clipboard_impl.h
#include "core/common/clipboard/clipboard.h"namespace OHOS::Ace::Platform {class ClipboardImpl final : public Clipboard {public:explicit ClipboardImpl(const RefPtr<TaskExecutor>& taskExecutor) : Clipboard(taskExecutor) {}~ClipboardImpl() override = default;void SetData(const std::string& data, CopyOptions copyOption = CopyOptions::InApp, bool isDragData = false) override;}
}
// 位于 arkui_for_android/capability/java/jni/clipboard/clipboard_impl.cpp
#include "adapter/android/capability/java/jni/clipboard/clipboard_impl.h"
#include "adapter/android/capability/java/jni/clipboard/clipboard_jni.h"namespace OHOS::Ace::Platform {void ClipboardImpl::SetData(const std::string& data, CopyOptions copyOption, bool isDragData){// 对 SetData 实现,最终ClipboardJni::SetData(data)taskExecutor_->PostTask([data] { ClipboardJni::SetData(data); }, TaskExecutor::TaskType::PLATFORM, "ArkUI-XClipboardImplSetData");}
}

再通过JNI实现C++Java交互:

// 位于 arkui_for_android/capability/java/jni/clipboard/clipboard_jni.cpp
static const char CLIPBOARD_PLUGIN_CLASS_NAME[] = "ohos/ace/adapter/capability/clipboard/ClipboardPluginBase";
static const JNINativeMethod METHODS[] = {{ .name = "nativeInit", .signature = "()V", .fnPtr = reinterpret_cast<void*>(ClipboardJni::NativeInit) },
};
static const char METHOD_SET_DATA[] = "setData";
static const char SIGNATURE_SET_DATA[] = "(Ljava/lang/String;)V";// JNI_OnLoad
bool ClipboardJni::Register(std::shared_ptr<JNIEnv> env)
{// 动态注册 nativeInit 方法,java侧调用jclass clazz = env->FindClass(CLIPBOARD_PLUGIN_CLASS_NAME);bool ret = env->RegisterNatives(clazz, METHODS, ArraySize(METHODS)) == 0;return true;
}void ClipboardJni::NativeInit(JNIEnv* env, jobject object)
{jclass clazz = env->GetObjectClass(object);g_pluginMethods.setData = env->GetMethodID(clazz, METHOD_SET_DATA, SIGNATURE_SET_DATA);
}bool ClipboardJni::SetData(const std::string& data)
{auto env = JniEnvironment::GetInstance().GetJniEnv();jstring jData = env->NewStringUTF(data.c_str());// 反射调用 ClipboardPluginAosp.java setData方法env->CallVoidMethod(g_clipboardObj.get(), g_pluginMethods.setData, jData);if (jData != nullptr) {env->DeleteLocalRef(jData);}return true;
}

最终通过ClipboardManager#setData() ,将ArkTS中设置的内容,给到Android的系统粘贴板。

// 位于 arkui_for_android 仓库打出的 arkui_android_adapter.jar 包中
public class ClipboardPluginAosp extends ClipboardPluginBase {private final ClipboardManager clipManager;public ClipboardPluginAosp(Context context) {this.clipManager = (ClipboardManager context.getSystemService(Context.CLIPBOARD_SERVICE);nativeInit();}@Overridepublic void setData(String data) {if (clipManager != null) {ClipData clipData = ClipData.newPlainText(null, data);clipManager.setPrimaryClip(clipData);}}
}

iOS平台的实现和Android平台类似,原理都是相通的。

06

小结

通过这一章,我们学到了ArkUI-X的环境搭建、项目创建和打包流程,探索了ArkTS编写的项目,编译后字节码文件如何与ArkUI对接,了解了ArkUI-X在Android平台上的实现方案,以及ArkUI-X如何适配系统平台能力。ArkUI-X 属于后来者,设计之初应该借鉴过其它跨平台方案,汲取了优秀设计,才形成目前的形态。今后在跨平台的实现上,我们又多了一种选择。

参考
  • ArkUI-X仓库地址:https://gitee.com/arkui-x

  • ArkUI-arkui_ace_engine仓库地址:https://gitee.com/openharmony/arkui_ace_engine

  • 深入理解arkui_ace_engine:https://juejin.cn/post/7305235970286485515

相关文章:

鸿蒙跨平台框架ArkUI-X

01 引言 目前&#xff0c;移动端主流跨平台方案有Flutter、React Native、uni-app等等&#xff0c;还有刚推出不久的Compose-Multiplatform&#xff0c;真所谓是百花齐放。这些框架各有特点&#xff0c;技术实现各有差异&#xff0c;比如Flutter通过Dart编写的UI描述对接Flutte…...

第7章 wireshark(网络安全防御实战--蓝军武器库)

网络安全防御实战--蓝军武器库是2020年出版的&#xff0c;已经过去3年时间了&#xff0c;最近利用闲暇时间&#xff0c;抓紧吸收&#xff0c;总的来说&#xff0c;第7章开始学习抓包工具wireshark&#xff0c;如果你怀疑自己的电脑中毒了&#xff0c;那么用wireshark可以很轻松…...

【AI】神经网络|机器学习——图解Transformer(完整版)

Transformer是一种基于注意力机制的序列模型,最初由Google的研究团队提出并应用于机器翻译任务。与传统的循环神经网络(RNN)和卷积神经网络(CNN)不同,Transformer仅使用自注意力机制(self-attention)来处理输入序列和输出序列,因此可以并行计算,极大地提高了计算效率…...

002-SpringCloud-OpenFeign(远程调用)

SpringCloud-OpenFeign 1.引入依赖2.编写一个远程调用接口3.测试 1.引入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId> </dependency><dependencyManageme…...

基于类型的声明接收props

在 Vue 3 中&#xff0c;除了运行时声明这种常见方式&#xff0c;还可以通过基于类型的声明、解构赋值等方式来接收 props&#xff0c;下面为你详细介绍&#xff1a; 1. 基于类型的声明 这种方式借助 TypeScript 的类型系统来定义 props&#xff0c;具有类型检查和代码提示的…...

多方安全计算(MPC)电子拍卖系统

目录 一、前言二、多方安全计算(MPC)与电子拍卖系统概述2.1 多方安全计算(MPC)的基本概念2.2 电子拍卖系统背景与需求三、MPC电子拍卖系统设计原理3.1 系统总体架构3.2 电子拍卖中的安全协议3.3 数学与算法证明四、数据加解密模块设计五、GPU加速与系统性能优化六、GUI设计与系…...

使用QT + 文件IO + 鼠标拖拽事件 + 线程 ,实现大文件的传输

第一题、使用qss&#xff0c;通过线程&#xff0c;使进度条自己动起来 mythread.h #ifndef MYTHREAD_H #define MYTHREAD_H#include <QObject> #include <QThread> #include <QDebug>class mythread : public QThread {Q_OBJECT public:mythread(QObject* …...

【无人机路径规划】基于麻雀搜索算法(SSA)的无人机路径规划(Matlab)

效果一览 代码获取私信博主基于麻雀搜索算法&#xff08;SSA&#xff09;的无人机路径规划&#xff08;Matlab&#xff09; 一、算法背景与核心思想 麻雀搜索算法&#xff08;Sparrow Search Algorithm, SSA&#xff09;是一种受麻雀群体觅食行为启发的元启发式算法&#xff0…...

基于物联网技术的分布式光伏监控系统设计与实现

一、分布式光伏发电系统标准规范 1.常见应用场景 2.并网标准 Q/GDW1480-2015《分布式电源接入电网技术规定》 分布式电源并网电压等级可根据各并网点装机容量进行初步选择&#xff0c;推荐如下&#xff1a; 8kW 及以下可接入220V&#xff1b; 8kW~400kW可接入380V&#xf…...

阿里发布新开源视频生成模型Wan-Video,支持文生图和图生图,最低6G就能跑,ComFyUI可用!

Wan-Video 模型介绍&#xff1a;包括 Wan-Video-1.3B-T2V 和 Wan-Video-14B-T2V 两个版本&#xff0c;分别支持文本到视频&#xff08;T2V&#xff09;和图像到视频&#xff08;I2V&#xff09;生成。14B 版本需要更高的 VRAM 配置。 Wan2.1 是一套全面开放的视频基础模型&…...

27. Harmonyos Next仿uv-ui 组件NumberBox 步进器组件禁用状态

温馨提示&#xff1a;本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦&#xff01; 文章目录 1. 组件介绍2. 效果展示3. 禁用状态设置3.1 整体禁用3.2 输入框禁用3.3 长按禁用 4. 完整示例代码5. 知识点讲解5.1 禁用状态属性5.2 禁用…...

【软件工程】一篇入门UML建模图(状态图、活动图、构件图、部署图)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;软件开发必练内功_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前…...

AI智能导航站HTML5自适应源码帝国cms7.5模板

源码名称&#xff1a;AI导航站HTML5自适应源码帝国cms7.5模板 开发环境&#xff1a;帝国cms 7.5 安装环境&#xff1a;phpmysql var code "4d33ef8e-9e38-43b9-b37b-38f75944ecc9" 带软件采集&#xff0c;可以挂着自动采集发布&#xff0c;无需人工操作&#xff0…...

Redis 发布订阅模式详解:实现高效的消息通信

目录 引言 1. 什么是 Redis 发布订阅模式&#xff1f; 1.1 定义 1.2 核心概念 2. Redis 发布订阅的工作原理 2.1 基本流程 2.2 示例 2.3 频道与模式订阅 3. Redis 发布订阅的使用场景 3.1 实时消息通知 3.2 事件驱动架构 3.3 日志收集与分发 3.4 分布式锁与协调 4…...

ES的预置分词器

Elasticsearch&#xff08;简称 ES&#xff09;提供了多种预置的分词器&#xff08;Analyzer&#xff09;&#xff0c;用于对文本进行分词处理。分词器通常由字符过滤器&#xff08;Character Filters&#xff09;、分词器&#xff08;Tokenizer&#xff09;和词元过滤器&#…...

MPPT与PWM充电原理及区别详解

MPPT&#xff08;最大功率点跟踪&#xff09;和PWM&#xff08;脉宽调制&#xff09;是太阳能充电控制器中常用的两种技术&#xff0c;它们在原理、效率和适用场景上有显著区别。以下是两者的详细对比&#xff1a; 1. 工作原理 PWM&#xff08;脉宽调制&#xff09; 核心机制…...

【AGI】通往AGI的复兴号:模型工具演进与技术路径优化

通往AGI的复兴号&#xff1a;模型工具演进与技术路径优化 一、核心模型与工具技术指标及场景分析1. 边缘计算标杆&#xff1a;GLM-PC&#xff08;2024年11月&#xff09;2. 长文本处理王者&#xff1a;DeepSeek R1&#xff08;2025年1月&#xff09;3. 轻量化开源代表&#xff…...

java2025年常见设计模式面试题

1. 请解释建造者模式&#xff08;Builder Pattern&#xff09;及其应用场景。 答案&#xff1a; 建造者模式用于创建一个复杂的对象&#xff0c;同时允许用户只通过指定复杂对象的类型和内容就能构建它们&#xff0c;隐藏了复杂的构建逻辑。 示例&#xff1a; public class C…...

探索CAMEL:揭开多智能体系统的神秘面纱

在人工智能领域,多智能体系统(Multi-Agent Systems, MAS)一直是一个充满活力和潜力的研究方向。随着大语言模型(LLM)的快速发展,智能体之间的协作与交互变得更加复杂和智能。今天,我们要介绍的是一个名为CAMEL(Communicative Agents for “Mind” Exploration of Large…...

el-pagination的使用说明

<el-paginationv-model:current-page"pageNo" //当前第几页v-model:page-size"pageSize" //每页显示多少条数据:page-sizes"[10, 20, 30]" //控制每页显示的条数:small"true" //控制分页器大小:disabled&quo…...

NSC_BUILDER:Switch游戏文件管理的全能解决方案

NSC_BUILDER&#xff1a;Switch游戏文件管理的全能解决方案 【免费下载链接】NSC_BUILDER Nintendo Switch Cleaner and Builder. A batchfile, python and html script based in hacbuild and Nuts python libraries. Designed initially to erase titlerights encryption fro…...

【八股必备】多线程面试题2

第一部分&#xff1a;线程基础与概念篇1. 线程模型面试官&#xff1a;先来个基础题&#xff0c;Java程序里的线程和操作系统线程是什么关系&#xff1f;是一回事吗&#xff1f;候选人&#xff1a;好的。在绝大多数情况下&#xff0c;比如我们常用的Windows、Linux系统&#xff…...

CCS:Code Composer Studio 12.8.1 窗口颜色改为深色

Code Composer Studio (CCS) 基于 Eclipse 平台开发&#xff0c;要将其界面改为深色模式&#xff0c;最推荐且有效的方法是安装 Eclipse Color Theme 插件。以下是针对 CCS 12.8.1 的具体操作步骤&#xff1a;&#x1f6e0;️ 第一步&#xff1a;安装主题插件在 CCS 菜单栏中&a…...

基于Hunyuan-MT-7B的算法竞赛题解翻译系统

基于Hunyuan-MT-7B的算法竞赛题解翻译系统 1. 引言 算法竞赛是全球程序员和算法爱好者展示实力的舞台&#xff0c;但语言障碍常常成为知识共享的壁垒。一道优秀的解题思路&#xff0c;可能因为语言不通而无法被更多人学习借鉴。传统的机器翻译工具在面对算法题解中的专业术语…...

如何用kill-doc解决30+文档平台下载难题:免费高效的文档获取方案

如何用kill-doc解决30文档平台下载难题&#xff1a;免费高效的文档获取方案 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档&#xff0c;但是相关网站浏览体验不好各种广告&#xff0c;各种登录验证&#xff0c;需要很多步骤才能下载文档&#xff0c;该脚本…...

ADS 2025瞬态仿真实战:手把手教你搞定PCB微带线串扰分析(含变量单位避坑指南)

ADS 2025瞬态仿真实战&#xff1a;手把手教你搞定PCB微带线串扰分析&#xff08;含变量单位避坑指南&#xff09; 作为一名硬件工程师&#xff0c;在高速PCB设计中遇到串扰问题就像在迷宫里寻找出口——看似简单却处处暗藏陷阱。特别是当你在ADS 2025中按照教程一步步设置参数&…...

滑模控制消抖新思路:双曲正切函数VS饱和函数效果实测对比

滑模控制消抖技术深度对比&#xff1a;双曲正切函数与饱和函数的实战解析 在智能控制算法的演进历程中&#xff0c;滑模控制&#xff08;SMC&#xff09;因其强鲁棒性成为处理系统不确定性和外部干扰的利器。但传统符号函数带来的高频抖振问题&#xff0c;一直是工程师们亟待解…...

Vue项目中el-tabs标签栏的5个高级用法与避坑指南

Vue项目中el-tabs标签栏的5个高级用法与避坑指南 在Vue生态中&#xff0c;Element UI的el-tabs组件是构建标签式界面的首选方案。但很多开发者仅停留在基础使用层面&#xff0c;未能充分发挥其潜力。本文将揭示五个高阶技巧&#xff0c;助你打造更灵活、高效的标签系统。 1. 标…...

PCB设计实战:数字模拟隔离的元件抉择——从0Ω电阻到磁珠的精准应用

1. 数字模拟隔离的基础原理与挑战 在混合信号电路设计中&#xff0c;数字电路和模拟电路就像两个性格迥异的邻居。数字电路工作时会产生高频开关噪声&#xff0c;就像隔壁装修时的电钻声&#xff1b;而模拟电路对噪声极其敏感&#xff0c;如同正在录音的麦克风。这时候&#xf…...

Android 基于ViewPager2+ExoPlayer+VideoCache 打造短视频无缝预加载方案

1. 为什么需要短视频无缝预加载方案 刷短视频已经成为现代人日常娱乐的重要方式&#xff0c;但卡顿、加载慢这些问题总是让人抓狂。想象一下&#xff0c;当你滑动到下一个视频时&#xff0c;如果出现黑屏等待&#xff0c;体验就会大打折扣。这正是我们需要实现无缝预加载的关键…...