【适配鸿蒙next】Flutter 新一代混合栈管理框架
前言
据最新消息显示,华为今年下半年将全面转向其自主平台HarmonyOS,放弃Android系统。
报道中提到,下一版HarmonyOS预计将随华为即将推出的Mate 70旗舰系列一起发布。
据悉,HarmonyOS Next 已经扩展到4000个应用程序,其中包括支付宝和麦当劳。
按照消息人士的说法,HarmonyOS Next的应用总数将在年内增至5000个,华为的目标是在短期内达到500000个。
HarmonyOS Next从零开始设计,由华为自主开发操作系统。虽然最初这套代码是为物联网设备编写,但华为很快意识到,它需要通过开发自己的操作系统来最大限度地降低外界的打压和限制。
事实上,华为正在通过自己的努力,让大家看到第三个主流智能手机操作系统,并与苹果的iOS和Android展开竞争。
本文主要讲Flutter 新一代混合栈管理框架
简介
Fusion 是新一代的混合栈管理框架,用于 Flutter 与 Native 页面统一管理,并支持页面通信、页面生命周期监听等功能。Fusion 即 融合,我们的设计初衷就是帮助开发者在使用 Flutter 与 Native 进行混合开发时尽量感受不到两者的隔阂,提升开发体验。此外,Fusion 彻底解决了混合开发过程中普遍存在的黑屏、白屏、闪屏等问题,更加适合重视用户体验的App使用。
从 4.0 开始,Fusion 已完成纯鸿蒙平台(HarmonyOS Next/OpenHarmony,以下简称 HarmonyOS)的适配,开发者可以在Android、iOS、HarmonyOS上得到完全一致的体验。(HarmonyOS 的 Flutter SDK 可以在这里获取)
OSAndroidiOSHarmonyOSSDK5.0(21)+11.0+4.1(11)+
Fusion 采用引擎复用方案,在 Flutter 与 Native 页面多次跳转情况下,APP 始终仅有一份 FlutterEngine 实例,因此拥有更好的性能和更低的内存占用。
Fusion 也是目前仅有的支持混合开发时应用在后台被系统回收后,所有Flutter页面均可正常恢复的混合栈框架。
开始使用
0、准备
在开始前需要按照 Flutter 官方文档,将 Flutter Module 项目接入到 Android、iOS、HarmonyOS 工程中。
1、初始化
Flutter 侧
使用 FusionApp 替换之前使用的 App Widget,并传入所需路由表,默认路由表和自定义路由表可单独设置也可同时设置。
void main() {runApp(FusionApp(// 默认路由表routeMap: routeMap,// 自定义路由表customRouteMap: customRouteMap,));
}// 默认路由表,使用默认的 PageRoute
// 使用统一的路由动画
final Map<String, FusionPageFactory> routeMap = {'/test': (arguments) => TestPage(arguments: arguments),kUnknownRoute: (arguments) => UnknownPage(arguments: arguments),
};// 自定义路由表,可自定义 PageRoute
// 比如:某些页面需要特定的路由动画则可使用该路由表
final Map<String, FusionPageCustomFactory> customRouteMap = {'/mine': (settings) => PageRouteBuilder(opaque: false,settings: settings,pageBuilder: (_, __, ___) => MinePage(arguments: settings.arguments as Map<String, dynamic>?)),
};
P.S: kUnknownRoute 表示未定义路由
注意:如果项目使用了 flutter_screenutil,需要在 runApp 前调用 Fusion.instance.install(),没有使用 flutter_screenutil则无须该步骤。
void main() {Fusion.instance.install();runApp(FusionApp(// 默认路由表routeMap: routeMap,// 自定义路由表customRouteMap: customRouteMap,));
}
Android 侧
在 Application 中进行初始化,并实现 FusionRouteDelegate 接口
class MyApplication : Application(), FusionRouteDelegate {override fun onCreate() {super.onCreate()Fusion.install(this, this)}override fun pushNativeRoute(name: String?, arguments: Map<String, Any>?) {// 根据路由 name 跳转对应 Native 页面}override fun pushFlutterRoute(name: String?, arguments: Map<String, Any>?) {// 根据路由 name 跳转对应 Flutter 页面// 可在 arguments 中存放参数判断是否需要打开透明页面}
}
iOS 侧
在 AppDelegate 中进行初始化,并实现 FusionRouteDelegate 代理
@UIApplicationMain
@objc class AppDelegate: UIResponder, UIApplicationDelegate, FusionRouteDelegate {func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {...Fusion.instance.install(self)...return true}func pushNativeRoute(name: String?, arguments: Dictionary<String, Any>?) {// 根据路由 name 跳转对应 Native 页面}func pushFlutterRoute(name: String?, arguments: Dictionary<String, Any>?) {// 根据路由 name 跳转对应 Flutter 页面// 可在 arguments 中存放参数判断是否需要打开透明页面// 可在 arguments 中存放参数判断是 push 还是 present}
}
HarmonyOS 侧
在 UIAbility 中进行初始化,并实现 FusionRouteDelegate 代理
export default class EntryAbility extends UIAbility implements FusionRouteDelegate {private static TAG = 'EntryAbility'private mainWindow: window.Window | null = nullprivate windowStage: window.WindowStage | null = nulloverride async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {await Fusion.instance.install(this.context, this)GeneratedPluginRegistrant.registerWith(Fusion.instance.defaultEngine!)}pushNativeRoute(name: string, args: Map<string, Object> | null): void {// 根据路由 name 跳转对应 Native 页面}pushFlutterRoute(name: string, args: Map<string, Object> | null): void {// 根据路由 name 跳转对应 Flutter 页面// 可在 arguments 中存放参数判断是否需要打开透明页面}
}
2、Flutter 容器
普通页面模式
Android 侧
通过 FusionActivity(或其子类) 创建 Flutter 容器,启动容器时需要使用 Fusion 提供的 buildFusionIntent 方法,其中参数 transparent 需设为 false。其 xml 配置参考如下(如果使用 FusionActivity 则不用配置):
<activityandroid:name=".CustomFusionActivity"android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"android:exported="false"android:hardwareAccelerated="true"android:launchMode="standard"android:theme="@style/FusionNormalTheme"android:windowSoftInputMode="adjustResize" />
iOS 侧
通过 FusionViewController (或其子类)创建 Flutter 容器,push 和 present 均支持。FusionViewController 默认隐藏了 UINavigationController。
在 iOS 中需要处理原生右滑退出手势和 Flutter 手势冲突的问题,解决方法也很简单:只需在自定义的 Flutter 容器中实现 FusionPopGestureHandler 并在对应方法中启用或者关闭原生手势即可,这样可以实现如果当前 Flutter 容器存在多个 Flutter 页面时,右滑手势是退出 Flutter 页面,而当 Flutter 页面只有一个时则右滑退出 Flutter 容器。
// 启用原生手势func enablePopGesture() {// 以下代码仅做演示,不可直接照搬,需根据APP实际情况自行实现navigationController?.interactivePopGestureRecognizer?.isEnabled = true}// 关闭原生手势func disablePopGesture() {// 以下代码仅做演示,不可直接照搬,需根据APP实际情况自行实现navigationController?.interactivePopGestureRecognizer?.isEnabled = false}
HarmonyOS 侧
通过 FusionEntry(或其子类) 创建 Flutter 容器,启动容器时需要使用 Fusion 提供的 buildFusionParams 方法,也可直接使用 FusionPage。默认全屏模式。
const params = buildFusionParams(name, args, false, backgroundColor)this.mainLocalStorage?.setOrCreate('params', params)router.pushNamedRoute({name: FusionConstant.FUSION_ROUTE_NAME})
透明页面模式
Android 侧
使用方式与普通页面模式相似,只是buildFusionIntent 方法的参数 transparent 需设为 true,其 xml 配置参考如下:
<activityandroid:name=".TransparentFusionActivity"android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"android:exported="false"android:hardwareAccelerated="true"android:launchMode="standard"android:theme="@style/FusionTransparentTheme"android:windowSoftInputMode="adjustResize" />
iOS 侧
使用方式与普通页面模式相似:
let fusionVc = CustomViewController(routeName: name, routeArguments: arguments, transparent: true)
navController?.present(fusionVc, animated: false)
HarmonyOS 侧
使用方式与普通页面模式相似:
const params = buildFusionParams(name, args, true, backgroundColor)this.windowStage?.createSubWindow(FusionConstant.TRANSPARENT_WINDOW, (_, win) => {const record: Record<string, Object> = {'params': params}win.loadContentByName(FusionConstant.FUSION_ROUTE_NAME, new LocalStorage(record))win.showWindow()})
Flutter 侧
同时Flutter页面背景也需要设置为透明
子页面模式
子页面模式是指一个或多个 Flutter 页面同时嵌入到 Native 容器中的场景,如:使用Tab切换Flutter和原生页面,Fusion 支持多个 Flutter 页面嵌入同一个 Native 容器中
Android 侧
使用 FusionFragment 以支持子页面模式,创建 FusionFragment 对象需要使用 buildFusionFragment 方法
iOS 侧
与页面模式一样使用 FusionViewController
HarmonyOS 侧
与页面模式一样使用 FusionEntry,配合 buildFusionParams方法配置参数
自定义容器背景色
默认情况下容器的背景为白色,这是因为考虑到绝大多数的页面都是使用白色背景,但如果打开的首个Flutter页面的背景是其他颜色,比如夜间模式下页面为深灰色,此时是为了更好的视觉效果,可以自定义容器的背景色与首个Flutter页面的背景色一致。
Android 侧
在 buildFusionIntent 和 buildFusionFragment方法中参数 backgroundColor 设为所需背景色
iOS 侧
在创建 FusionViewController (或其子类)对象时,参数 backgroundColor 设为所需背景色
HarmonyOS 侧
在 buildFusionParams方法中参数 backgroundColor 设为所需背景色
3、路由API(FusionNavigator)
○push:将对应路由入栈,Navigator.pushNamed 与之等同,根据FusionRouteType分为以下几种方式:
○flutter模式: 在当前Flutter容器中将指定路由对应的Flutter页面入栈,如果没有则跳转kUnknownRoute对应Flutter页面
○flutterWithContainer模式: 创建一个新的Flutter容器,并将指定路由对应的Flutter页面入栈,如果没有则跳转kUnknownRoute对应Flutter页面。即执行FusionRouteDelegate的pushFlutterRoute
○native模式: 将指定路由对应的Native页面入栈,即执行FusionRouteDelegate的pushNativeRoute
○adaption模式: 自适应模式,默认类型。首先判断该路由是否是Flutter路由,如果不是则进入native模式,如果是再判断当前是否是页面是否是Flutter容器,如果是则进入flutter模式,如果不是则进入flutterWithContainer模式
●pop:在当前Flutter容器中将栈顶路由出栈,Navigator.pop 与之等同
●maybePop:在当前Flutter容器中将栈顶路由出栈,可被WillPopScope拦截
●replace:在当前Flutter容器中将栈顶路由替换为对应路由,Navigator.pushReplacementNamed 与之等同
●remove:在当前Flutter容器中移除对应路由
路由跳转与关闭等操作既可使用FusionNavigator的 API,也可使用Navigator中与之对应的API(仅上述提到的部分)
4、Flutter Plugin 注册
在 Android 和 iOS 平台上框架内部会自动注册插件,无须手动调用 GeneratedPluginRegistrant.registerWith 进行注册,但 HarmonyOS 必须手动调用该方法。
5、自定义 Channel
如果需要 Native 与 Flutter 进行通信,则需要自行创建 Channel,创建 Channel 方式如下(以 MethodChannel 为例):
Android 侧
①、与容器无关的方法
在 Application 中进行注册
val channel = Fusion.defaultEngine?.dartExecutor?.binaryMessenger?.let {MethodChannel(it,"custom_channel")
}
channel?.setMethodCallHandler { call, result ->
}
②、与容器相关的方法
在自实现的 FusionActivity、FusionFragmentActivity、FusionFragment 上实现 FusionMessengerHandler 接口,在 configureFlutterChannel 中创建 Channel,在 releaseFlutterChannel 释放 Channel
class CustomActivity : FusionActivity(), FusionMessengerHandler {override fun configureFlutterChannel(binaryMessenger: BinaryMessenger) {val channel = MethodChannel(binaryMessenger, "custom_channel")channel.setMethodCallHandler { call, result -> }}override fun releaseFlutterChannel() {channel?.setMethodCallHandler(null)channel = null}
}
iOS 侧
①、与容器无关的方法
在 AppDelegate 中进行注册
var channel: FlutterMethodChannel? = nil
if let binaryMessenger = Fusion.instance.defaultEngine?.binaryMessenger {channel = FlutterMethodChannel(name: "custom_channel", binaryMessenger: binaryMessenger)
}
channel?.setMethodCallHandler { (call: FlutterMethodCall, result: @escaping FlutterResult) in
}
②、与容器相关的方法
在自实现的 FusionViewController 上实现 FusionMessengerHandler 协议,在协议方法中创建 Channel
class CustomViewController : FusionViewController, FusionMessengerHandler {func configureFlutterChannel(binaryMessenger: FlutterBinaryMessenger) {channel = FlutterMethodChannel(name: "custom_channel", binaryMessenger: binaryMessenger)channel?.setMethodCallHandler { (call: FlutterMethodCall, result: @escaping FlutterResult) in}}func releaseFlutterChannel() {channel?.setMethodCallHandler(nil)channel = nil}
}
HarmonyOS 侧
①、与容器无关的方法
在 UIAbility 中进行注册
const binaryMessenger = Fusion.instance.defaultEngine?.dartExecutor.getBinaryMessenger()
const channel = new MethodChannel(binaryMessenger!, 'custom_channel')
channel.setMethodCallHandler({onMethodCall(call: MethodCall, result: MethodResult): void {}
})
②、与容器相关的方法
在自实现的 FusionEntry 上实现 FusionMessengerHandler 接口,在 configureFlutterChannel 中创建 Channel,在 releaseFlutterChannel 释放 Channel
export default class CustomFusionEntry extends FusionEntry implements FusionMessengerHandler, MethodCallHandler {private channel: MethodChannel | null = nullconfigureFlutterChannel(binaryMessenger: BinaryMessenger): void {this.channel = new MethodChannel(binaryMessenger, 'custom_channel')this.channel.setMethodCallHandler(this)}onMethodCall(call: MethodCall, result: MethodResult): void {result.success(`Custom Channel:${this}_${call.method}`)}releaseFlutterChannel(): void {this.channel?.setMethodCallHandler(null)this.channel = null}
}
BasicMessageChannel 和 EventChannel 使用也是类似
P.S.: 与容器相关的方法是与容器生命周期绑定的,如果容器不可见或者销毁了则无法收到Channel消息。
6、生命周期
应用生命周期监听:
①、在 Flutter 侧任意处注册监听皆可,并implements FusionAppLifecycleListener
②、根据实际情况决定是否需要注销监听
void main() {...FusionAppLifecycleBinding.instance.register(MyAppLifecycleListener());runApp(const MyApp());
}class MyAppLifecycleListener implements FusionAppLifecycleListener {@overridevoid onBackground() {print('onBackground');}@overridevoid onForeground() {print('onForeground');}
}
FusionAppLifecycleListener 生命周期回调函数:
●onForeground: 应用进入前台会被调用(首次启动不会被调用,Android 与 iOS 保持一致)
●onBackground: 应用退到后台会被调用
页面生命周期监听:
●①、在需要监听生命周期页面的 State 中 implements FusionPageLifecycleListener
●②、在 didChangeDependencies 中注册监听
●③、在 dispose 中注销监听
class LifecyclePage extends StatefulWidget {const LifecyclePage({Key? key}) : super(key: key);@overrideState<LifecyclePage> createState() => _LifecyclePageState();
}class _LifecyclePageState extends State<LifecyclePage>implements FusionPageLifecycleListener {@overrideWidget build(BuildContext context) {return Container();}@overridevoid didChangeDependencies() {super.didChangeDependencies();FusionPageLifecycleBinding.instance.register(this);}@overridevoid onPageVisible() {}@overridevoid onPageInvisible() {}@overridevoid onForeground() {}@overridevoid onBackground() {}@overridevoid dispose() {super.dispose();FusionPageLifecycleBinding.instance.unregister(this);}
}
PageLifecycleListener 生命周期回调函数:
●onForeground: 应用进入前台会被调用,所有注册了生命周期监听的页面都会收到
●onBackground: 应用退到后台会被调用,所有注册了生命周期监听的页面都会收到
●onPageVisible: 该 Flutter 页面可见时被调用,如:从 Native 页面或其他 Flutter 页面 push 到该 Flutter 页面时;从 Native 页面或其他 Flutter 页面 pop 到该 Flutter 页面时;应用进入前台时也会被调用。
●onPageInvisible: 该 Flutter 页面不可见时被调用,如:从该 Flutter 页面 push 到 Native 页面或其他 Flutter 页面时;如从该 Flutter 页面 pop 到 Native 页面或其他 Flutter 页面时;应用退到后台时也会被调用。
7、全局通信
支持消息在应用中的传递,可以指定 Native 还是 Flutter 或者全局接收和发送。
注册消息监听
Flutter侧
●①、在需要监听消息的类中 implements FusionNotificationListener,并复写 onReceive 方法,该方法可收到发送过来的消息
●②、在合适时机注册监听
●③、在合适时机注销监听
class TestPage extends StatefulWidget {@overrideState<TestPage> createState() => _TestPageState();
}class _TestPageState extends State<TestPage> implements FusionNotificationListener {@overridevoid onReceive(String name, Map<String, dynamic>? body) {}@overridevoid didChangeDependencies() {super.didChangeDependencies();FusionNotificationBinding.instance.register(this);}@overridevoid dispose() {super.dispose();FusionNotificationBinding.instance.unregister(this);}
}
Native侧
●①、在需要监听消息的类中实现 FusionNotificationListener 接口,并复写 onReceive 方法,该方法可收到发送过来的消息
●②、在适当时机使用 FusionNotificationBinding 的 register 方法注册监听
●③、在适当时机使用 FusionNotificationBinding 的 unregister 方法注销监听
发送消息
三端均可使用FusionNavigator 的 sendMessage 方法来发送消息,根据使用FusionNotificationType 不同类型有不同效果:
●flutter: 仅 Flutter 可以收到
●native: 仅 Native 可以收到
●global(默认): Flutter 和 Native 都可以收到
8、返回拦截
在纯 Flutter 开发中可以使用WillPopScope组件拦截返回操作,Fusion 也完整支持该功能,使用方式与在纯 Flutter 开发完全一致,此外使用FusionNavigator.maybePop的操作也可被WillPopScope组件拦截。
9、状态恢复
Fusion 支持 Android 和 iOS 平台 APP 被回收后 Flutter 路由的恢复。
总结
总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。随着鸿蒙的不断发展以及国家的大力支持,未来鸿蒙职位肯定会迎来一个大的爆发,只有积极应对变化,不断学习和提升自己,我们才能在这个变革的时代中立于不败之地。
相关文章:
【适配鸿蒙next】Flutter 新一代混合栈管理框架
前言 据最新消息显示,华为今年下半年将全面转向其自主平台HarmonyOS,放弃Android系统。 报道中提到,下一版HarmonyOS预计将随华为即将推出的Mate 70旗舰系列一起发布。 据悉,HarmonyOS Next 已经扩展到4000个应用程序,…...
车载电子电气架构 --- 车载信息安全
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…...
【数据结构(邓俊辉)学习笔记】图04——双连通域分解
文章目录 0. 概述1 关节点与双连通域2 蛮力算法3 可行算法4 实现5 示例6 复杂度 0. 概述 学习下双连通域分解,这里略微有一点点难,这个算是DFS算法的非常非常经典的应用,解决的问题也非常非常有用。 1 关节点与双连通域 连通性很好理解&am…...
UI学习(二)
UI学习(二) 文章目录 UI学习(二)布局子视图手动布局自动布局 导航控制器导航控制器基础导航控制器的切换导航栏工具栏 分栏控制器分栏控制器协议部分的内容UITableView基础部分相关的协议函数高级协议与单元格 多界面传值 布局子视…...
【嵌入式】波特率9600,发送8个字节需要多少时间,如何计算?
问题: 波特率9600,发送 01 03 00 00 00 04 44 09 (8字节) 需要多少时间,如何计算? 在计算发送数据的时间时,首先要考虑波特率以及每个字符的数据格式。对于波特率9600和标准的UART数据格式(1个起始位&…...
jmeter -n -t 使用非GUI模式运行脚本说明
命令模式下执行jmx文件 jmeter -n -t fatie.jmx -l results\t4.jtl -e -o results\h1 表示以命令行模式运行当前目录下的脚本fatie.jmx,将结果存入当前目录下的results\t1.jtl,并且生成html格式的报告,写入文件夹results\h1。 说明:生成结果的文件夹r…...
网络流媒体协议——HLS协议
HTTP 实时流媒体(HTTP Live Streaming,HLS)协议是苹果公司提出的主要用于直播的流媒体协议。一个完整的基于HLS协议的流媒体直播系统由四部分组成,即音视频采集器、媒体服务器、媒体分发器和播放客户端。 媒体服务器 媒体服务器的…...
Linux服务器扩容及磁盘分区(LVM和非LVM)
Linux扩容及磁盘分区(LVM和非LVM) 本文主要介绍了阿里云服务器centos的扩容方法:非LVM分区扩容方法(系统盘),以及磁盘改LVM并分区(数据盘)。主要是ext4文件系统及xfs磁盘scsi MBR分…...
支持向量机
支持向量机(SVM) 支持向量机(Support Vector Machine, SVM)是一种用于分类和回归任务的监督学习算法。SVM 的核心思想是找到一个最优的决策边界(或称为超平面),以最大化不同类别之间的间隔。以…...
Kafka 架构
1 整体架构 1.1 Zookeeper Zookeeper 是一个分布式协调服务,用于管理 Kafka 的元数据。它负责维护 Kafka 集群的配置信息、Broker 列表和分区的 Leader 信息。 Zookeeper 确保了 Kafka 集群的高可用性和可靠性。 但 Zookeeper 已经成为 Kafka 性能瓶颈,…...
iOS 查看runtime源码的几种方法
目录 前言 查看runtime 源码方法 1.下载 Apple 官方提供的源代码 2.通过 GitHub 访问镜像 3.使用命令行工具查看 4.示例 前言 这篇博客主要介绍了查看iOS runtime源代码的方法。 查看runtime 源码方法 查看iOS runtime源码的方法包括以下几个步骤: 1.下载 A…...
底板外设倒灌到处理器分析
在嵌入式系统中,底板外设通常与处理器通过各种接口(如UART、SPI、I2C、GPIO等)进行连接。这些外设可能包括传感器、执行器、存储器、通信模块等。倒灌是指当外设向处理器提供的信号电平超出了处理器能够接受的范围,导致处理器无法…...
使用贝塞尔曲线实现一个iOS时间轴
UI效果 实现的思路 就是通过贝塞尔曲线画出时间轴的圆环的路径,然后 使用CAShaper来渲染UI,再通过 animation.beginTime [cilrclLayer convertTime:CACurrentMediaTime() fromLayer:nil] circleTimeOffset 来设置每个圆环的动画开始时间, …...
【深度学习】深度学习之巅:在 CentOS 7 上打造完美Python 3.10 与 PyTorch 2.3.0 环境
【深度学习】深度学习之巅:在 CentOS 7 上打造完美Python 3.10 与 PyTorch 2.3.0 环境 大家好 我是寸铁👊 总结了一篇【深度学习】深度学习之巅:在 CentOS 7 上打造完美Python 3.10 与 PyTorch 2.3.0 环境✨ 喜欢的小伙伴可以点点关注 &#…...
在docker容器中使用gdb调试python3.11的进程
gdb调试python进程的前提条件 安装python及python调试信息安装gdb工具安装python-gdb.py扩展 安装过程 我们使用docker来安装以上内容,Dockerfile文件内容如下: FROM docker.io/centos:7.4.1708# 安装依赖 RUN yum install -y -q epel-release &…...
堆排序要点和难点以及具体案例应用
堆排序(Heap Sort)是一种基于堆数据结构的排序算法。下面我将以分点表示和归纳的方式,结合相关数字和信息,详细描述堆排序的PTA(Programming and Testing Approach,编程与测试方法)。 1. 堆排序原理 堆排序是一种树形选择排序,利用了完全二叉树的性质,通过构建最大堆…...
pyspark中使用mysql jdbc报错java.lang.ClassNotFoundException: com.mysql.jdbc.Driver解决
报错信息: py4j.protocol.Py4JJavaError: An error occurred while calling o33.load. : java.lang.ClassNotFoundException: com.mysql.jdbc.Driver 我的解决方法: 这个报错就是提示你找不到jar包,所以你需要去下载一个和你mysql版本匹配的j…...
对称加密系统解析
目录 1.概述 2. 对称密码类型 3. 对称加密优缺点 4. 对称加密算法 4.1 DES 4.2 3DES 4.3 AES 4.4 SM1 4.5 SM4 1.概述 对称加密,是指在加密和解密时使用同一秘钥的方式。秘钥的传送和保存的保护非常重要,务必不要让秘…...
初识 java 2
1. idea 的调试 1. 点击鼠标左键设置断点 2.运行到断点处 点击 或点击鼠标右键,再点击 使代码运行到断点处,得到 2. 输出到控制台 System.out.println(value);//输出指定的内容,并换行 value 要打印的内容System.out.print(value);…...
云端狂飙:Django项目部署与性能优化的极速之旅
Hello,我是阿佑,这次阿佑将手把手带你亲自踏上Django项目从单机到云端的全过程,以及如何通过Docker实现项目的无缝迁移和扩展。不仅详细介绍了Docker的基本概念和操作,还深入探讨Docker Compose、Swarm和Kubernetes等高级工具的使…...
GDPU JavaWeb 大结局篇(持续更新中)
GDPUJavaWeb程序设计复习,习题集,重点知识总结,一篇就够了。 实验复习 JavaWeb代码复习,在专栏也可查阅。 课后巩固习题 1 【单选题】下列说法正确的是( D ) A、在B/S结构中,结果应用软件发生了改变,就必须通知所有的客户端重新…...
Linux系统信息的查看
目录 前言一、系统环境二、查看系统IP地址信息2.1 ifconfig命令2.2 ip address命令 三、查看系统端口信息3.1 nmap命令3.2 netstat命令 四、查看系统进程信息4.1 ps命令4.2 kill命令 五、查看系统监控信息5.1 top命令5.2 df命令iostat命令5.3 sar命令 总结 前言 本篇文章介绍查…...
LE Audio音频广播新功能Auracast介绍
LE Audio音频广播新功能Auracast介绍 /*! \copyright Copyright (c) 2019-2022 Qualcomm Technologies International, Ltd. All Rights Reserved. Qualcomm Technologies International, Ltd. Confidential and Proprietary. \file audio_sources.h \defgroup audio_so…...
一文学习yolov5 实例分割:从训练到部署
一文学习yolov5 实例分割:从训练到部署 1.模型介绍1.1 YOLOv5结构1.2 YOLOv5 推理时间 2.构建数据集2.1 使用labelme标注数据集2.2 生成coco格式label2.3 coco格式转yolo格式 3.训练3.1 整理数据集3.2 修改配置文件3.3 执行代码进行训练 4.使用OpenCV进行c部署参考文…...
【设计模式】行为型设计模式之 策略模式学习实践
介绍 策略模式(Strategy),就是⼀个问题有多种解决⽅案,选择其中的⼀种使⽤,这种情况下我们 使⽤策略模式来实现灵活地选择,也能够⽅便地增加新的解决⽅案。⽐如做数学题,⼀个问题的 解法可能有…...
lua中大数相乘的问题
math.maxinteger * 2 --> -2 原因:math.maxinteger的二进制 : 0111111111111111111111111111111111111111111111111111111111111111 往左移位,最右加一个0,是 1111111111111111111111111111111111111111111111111111111111111…...
第一个SpringBoot项目
目录 💭1、新建New Project IDEA2023版本创建Sping项目只能勾选17和21,却无法使用Java8?🌟 2、下载JDK 17🌟 💭2、项目创建成功界面 1、目录 🌟 2、pom文件🌟 💭3、…...
Android 10.0 Launcher修改density禁止布局改变功能实现
1.前言 在10.0的系统rom定制化开发中,在关于Launcher3的定制化功能中,在有些功能需要要求改变系统原有的density屏幕密度, 这样就会造成Launcher3的布局变化,所以就不符合要求,接下来就来看下如何禁止改变density造成Launcher3布局功能 改变的实现 2.Launcher修改densit…...
CAN协议简介
协议简介 can协议是一种用于控制网络的通信协议。它是一种基于广播的多主机总线网络协议,常用于工业自动化和控制领域。can协议具有高可靠性、实时性强和抗干扰能力强的特点,被广泛应用于汽车、机械、航空等领域。 can协议采用了先进的冲突检测和错误检测…...
(二)JSX基础
什么是JSX 概念:JSX是JavaScript和XML(HTML)的缩写,表示在JS代码中编写HTML模版结构,它是React中编写UI模板的方式。 优势:1.HTML的声明式模版方法;2.JS的可编程能力 JSX的本质 JSX并不是标准…...
网站运营与维护是什么/企业培训心得
题目要求: 歌手比赛系统 对一次歌手比赛的成绩进行管理,输入每个选手的数据包括编号、姓名、10个评委的成绩,根据输入计算出总成绩和平均成绩(去掉最高分,去掉最低分)。 实现以下功能: &#x…...
门户网站建设课程设计/seo薪酬
打开vs,点击项目,查看属性,打开ssl 如果有什么危险提示,就允许 右击项目,选择属性 运行项目 本文转自毒逆天博客园博客,原文链接:http://www.cnblogs.com/dunitian/p/5248957.html,如…...
深圳团购网站设计/成都网站建设系统
CPU访问corePac内部资源(L1,L2)时的内存保护(通过设置内存的访问权限实现)等问题请参考下面两个blog,已经叙述的很详细。 "TI C66x DSP 系统events及其应用 - 2","TI C66x DSP …...
免费个人简历/360优化大师官方最新
先介绍下背景 非211,985本科毕业。一年半PHP经验,一年半前端经验,前端一直在做React开发。 半年之前,我是一个前端小小小白。多么小白呢? css调样式全靠试。盒模型,好像知道是啥?好像又不知道&a…...
无锡定制网站/免费行情网站
大家肯定有这样的经历,浏览网页的时候,左右两端广告,诸如“屠龙宝刀,点击就送”,以及最近火的不行的林子聪37传奇霸业什么“霸业面具,霸业吊坠”的魔性广告总是充斥我们的眼球。 当然有现成的扩展程序或者插…...
哪个网站做欧洲旅游攻略好/软文广告文案案例
目录 1、接口概念 2、声明接口类型 3、接口实现 1、接口概念 接口是对其他类型行为的概括与抽象。 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节。 在Go语言中接口(interface)是一种类型,一种抽象...