flutter和原生利用pigeon建立通道

首先导入依赖:

dependencies:
pigeon: ^10.0.0

image.png

定义一个文件:

/// 用于定于flutter和平台的桥接方法
/// @HostApi() 标记的,是用于 Flutter 调用原生的方法;
/// @FlutterApi() 标记的,是用于原生调用 Flutter 的方法;
/// @async 如果原生的方法,是步回调那种,你就可以使用这个标记;
/// 在项目根目录,运行以下命令生成平台代码
/// dart run pigeon --input pigeons/messages.dartimport 'package:pigeon/pigeon.dart';@ConfigurePigeon(PigeonOptions(dartOut: 'lib/pigeons/pigeon.dart',dartOptions: DartOptions(),// objcHeaderOut: '../isolarCloud/operation4ios/Flutter/SGFlutterBridge.h',// objcSourceOut: '../isolarCloud/operation4ios/Flutter/SGFlutterBridge.m',// objcOptions: ObjcOptions(),kotlinOut:'../iSolarCloud/LibBase/src/main/java/com/isolarcloud/libbase/flutter/SGFlutterBridge.kt',kotlinOptions: KotlinOptions(),
))
class CommonParams {String? pageName;Map<String?, Object?>? arguments;
}
class ApiParams {String? url;Map<String?, Object?>? arguments;
}/// Flutter调用原生的Api,全部放在一个抽象类中即可
@HostApi()abstract class SGHostApi {/// push至原生页面,参数:页面名称、参数void pushNativePage(CommonParams params);/// pop出当前页面,预留参数,可通过params.pageName pop到指定页面void popPage(CommonParams? params);/// 通过Key获取本地化文本数据(同步)String getLocalizedText(String? key);/// Flutter通过URL和arguments调用原生端接口,异步返回数据给Flutter端@asyncMap requestNativeApi(ApiParams apiParams);/// 是否允许开启Native页面的原生手势返回效果void enablePopRecognizer(bool enable);
}

运行命令行:
dart run pigeon --input pigeons/messages.dart

接着可以运行下:flutter pub get 的命令

自动会生成这个文件:

image.png

里面会实现SGHostApi的定义的方法:比如下面的方法就是自动生成:

/// push至原生页面,参数:页面名称、参数
Future<void> pushNativePage(CommonParams arg_params) async {final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>('dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.pushNativePage', codec,binaryMessenger: _binaryMessenger);final List<Object?>? replyList =await channel.send(<Object?>[arg_params]) as List<Object?>?;if (replyList == null) {throw PlatformException(code: 'channel-error',message: 'Unable to establish connection on channel.',);} else if (replyList.length > 1) {throw PlatformException(code: replyList[0]! as String,message: replyList[1] as String?,details: replyList[2],);} else {return;}
}

注意打开这个代码注释:意思是在你Android项目的某个路径下生成SGFlutterBridge文件。

kotlinOut:'../iSolarCloud/LibBase/src/main/java/com/isolarcloud/flutter/SGFlutterBridge.kt',
kotlinOptions: KotlinOptions(),

然后会在:上面这个路径下自动生成和原生的桥接方法,这里执行的是Android的方法,ios只需要打开:

  // objcHeaderOut: '../isolarCloud/operation4ios/Flutter/SGFlutterBridge.h',// objcSourceOut: '../isolarCloud/operation4ios/Flutter/SGFlutterBridge.m',// objcOptions: ObjcOptions(),

我们先看看原生和flutter项目的依赖:

image.png

在Android的项目settings.gradle中配置引用:

setBinding(new Binding([gradle: this]))
evaluate(new File(settingsDir,'../isolarcloud_flutter/.android/include_flutter.groovy')
)

以上操作就把两个项目关联在一起了。下面是自动生成的桥接方法,pigeon自动帮你实现:

/*** Flutter调用原生的Api,全部放在一个抽象类中即可** Generated interface from Pigeon that represents a handler of messages from Flutter.*/
interface SGHostApi {/** push至原生页面,参数:页面名称、参数 */fun pushNativePage(params: CommonParams)/** pop出当前页面,预留参数,可通过params.pageName pop到指定页面 */fun popPage(params: CommonParams?)/** Flutter通过URL和arguments调用原生端接口,异步返回数据给Flutter端 */fun requestNativeApi(apiParams: ApiParams, callback: (Result<String?>) -> Unit)/** 是否允许开启Native页面的原生手势返回效果 */fun enablePopRecognizer(enable: Boolean)/*** 调用原生toast* type:0 老版,1:国内,2:海外样式*/fun showToast(type: AppType, msg: String)/*** 调用原生toast* type:0 老版,1:国内,2:海外样式*/fun showLoading(show: Boolean, type: AppType, msg: String?)/** 获取用户信息 */fun getUserInfo(): String?companion object {/** The codec used by SGHostApi. */val codec: MessageCodec<Any?> by lazy {SGHostApiCodec}/** Sets up an instance of `SGHostApi` to handle messages through the `binaryMessenger`. */@Suppress("UNCHECKED_CAST")fun setUp(binaryMessenger: BinaryMessenger, api: SGHostApi?) {run {val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.pushNativePage", codec)if (api != null) {channel.setMessageHandler { message, reply ->val args = message as List<Any?>val paramsArg = args[0] as CommonParamsvar wrapped: List<Any?>try {api.pushNativePage(paramsArg)wrapped = listOf<Any?>(null)} catch (exception: Throwable) {wrapped = wrapError(exception)}reply.reply(wrapped)}} else {channel.setMessageHandler(null)}}run {val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.popPage", codec)if (api != null) {channel.setMessageHandler { message, reply ->val args = message as List<Any?>val paramsArg = args[0] as CommonParams?var wrapped: List<Any?>try {api.popPage(paramsArg)wrapped = listOf<Any?>(null)} catch (exception: Throwable) {wrapped = wrapError(exception)}reply.reply(wrapped)}} else {channel.setMessageHandler(null)}}run {val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.requestNativeApi", codec)if (api != null) {channel.setMessageHandler { message, reply ->val args = message as List<Any?>val apiParamsArg = args[0] as ApiParamsapi.requestNativeApi(apiParamsArg) { result: Result<String?> ->val error = result.exceptionOrNull()if (error != null) {reply.reply(wrapError(error))} else {val data = result.getOrNull()reply.reply(wrapResult(data))}}}} else {channel.setMessageHandler(null)}}run {val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.enablePopRecognizer", codec)if (api != null) {channel.setMessageHandler { message, reply ->val args = message as List<Any?>val enableArg = args[0] as Booleanvar wrapped: List<Any?>try {api.enablePopRecognizer(enableArg)wrapped = listOf<Any?>(null)} catch (exception: Throwable) {wrapped = wrapError(exception)}reply.reply(wrapped)}} else {channel.setMessageHandler(null)}}run {val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.showToast", codec)if (api != null) {channel.setMessageHandler { message, reply ->val args = message as List<Any?>val typeArg = AppType.ofRaw(args[0] as Int)!!val msgArg = args[1] as Stringvar wrapped: List<Any?>try {api.showToast(typeArg, msgArg)wrapped = listOf<Any?>(null)} catch (exception: Throwable) {wrapped = wrapError(exception)}reply.reply(wrapped)}} else {channel.setMessageHandler(null)}}run {val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.showLoading", codec)if (api != null) {channel.setMessageHandler { message, reply ->val args = message as List<Any?>val showArg = args[0] as Booleanval typeArg = AppType.ofRaw(args[1] as Int)!!val msgArg = args[2] as String?var wrapped: List<Any?>try {api.showLoading(showArg, typeArg, msgArg)wrapped = listOf<Any?>(null)} catch (exception: Throwable) {wrapped = wrapError(exception)}reply.reply(wrapped)}} else {channel.setMessageHandler(null)}}run {val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.isolarcloud_flutter.SGHostApi.getUserInfo", codec)if (api != null) {channel.setMessageHandler { _, reply ->var wrapped: List<Any?>try {wrapped = listOf<Any?>(api.getUserInfo())} catch (exception: Throwable) {wrapped = wrapError(exception)}reply.reply(wrapped)}} else {channel.setMessageHandler(null)}}}}
}

同步或者异步的去调用自动生成的方法:

Future<void> makeApiCall() async {var arguments = {"curPage": 1, "size": 10, "message_scene_code": 2};final stopwatch = Stopwatch()..start();await SGHostApi().requestNativeApi(ApiParams(arguments: arguments)).then((value) {print("数据回来的时间:${DateTime.now().millisecondsSinceEpoch}");stopwatch.stop();print("总共花费时间:${stopwatch.elapsedMilliseconds}毫秒");toast = "android 返回的数据==$value";// print("value===$value");setState(() {});});
}_getString(){SGHostApi().getLocalizedText("I18N_COMMON_SERVICE_AGREEMENT_DESCRIPTION").then((value){print("android 给过来的数据==$value");});setState(() {});
}

Android的代码:

class SingleFlutterActivity : FlutterActivity(), EngineBindingsDelegate {private val engineBindings: EngineBindings by lazy {EngineBindings(activity = this, delegate = this, entrypoint = FlutterRouter.DEMO_ENTRY_POINTER, initialRoute = "${FlutterRouter.DEMO_ROUTER}?psId=1234")}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)engineBindings.attach()/*** flutter 调用原生的方法* */SGHostApiget.setUp(getFlutterEngine()!!.getDartExecutor().getBinaryMessenger(), MyApi())SGHostApi.setUp(getFlutterEngine()!!.getDartExecutor().getBinaryMessenger(),FlutterToNativeApi() )}override fun onDestroy() {super.onDestroy()engineBindings.detach()}override fun provideFlutterEngine(context: Context): FlutterEngine? {return engineBindings.engine}override fun onNext() {val flutterIntent = Intent(this, LoginActivity::class.java)startActivity(flutterIntent)}/*** flutter 调用原生的方法,原生写法* */override fun onNext(str: String?) {val flutterIntent = Intent(this, FlutterToAndroidActivity::class.java)flutterIntent.putExtra("extraString", str)startActivity(flutterIntent)}/*** flutter 调用原生的方法* */class MyApi : SGHostApiget {override fun getString(): String {println("测试===6666")return "测试===6666,这里是Android的方法"}}/*** flutter 调用原生的方法* */class FlutterToNativeApi() : SGHostApi {/*** flutter调用原生跳原生页面* */override fun pushNativePage(params: CommonParams) {//params.pageName 页面名称非类名,不可直接创建实例/*val flutterIntent = Intent(this, params::class.java)flutterIntent.putExtra("extraString", str)startActivity(flutterIntent)*/}/*** flutter调用原生跳原生页面* */override fun popPage(params: CommonParams?) {//flutter调用Android去退出页面}/*** flutter调用原生 获取国际化字符串* */override fun getLocalizedText(key: String?): String {return I18nUtil.getString(key);}/*** flutter调用原生 获取网络信息 异步* */override fun requestNativeApi(apiParams: ApiParams,callback: (Result<Map<Any, Any?>>) -> Unit,) {/*val bitmap: Bitmap = BitmapFactory.decodeResource(BaseApplication.getApplication().resources, R.drawable.test_image)val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()bitmap.compress(Bitmap.CompressFormat.PNG, 50, outputStream)val size: Int = outputStream.size()println("字节大小: $size")val result: Result<Map<Any, Any?>> = Result.success(mapOf("name" to outputStream),)callback(result)*/val map: MutableMap<String, Any> = HttpRequest.getCommonParamMap()HttpUtil.postWithPath("/v1/devService/getDevModelUpgradeConfigList", /*apiParams.arguments*/map, object : HttpGlobalHandlerCallback<UpdateRequestBean?>() {override fun onSuccess(jsonResult: JsonResults<UpdateRequestBean?>) {// 处理成功返回的数据val data = jsonResult.result_data // 获取数据if (data is UpdateRequestBean) {data as UpdateRequestBean}println("开始传输时间: ${System.currentTimeMillis()}")callback(Result.success(data!!.toMap())) // 通过callback返回结果// 打印字节大小val byteArray = data?.toString()?.toByteArray(Charsets.UTF_8)val size = byteArray?.size ?: 0println("字节大小: $size")}fun UpdateRequestBean.toMap(): Map<Any, Any?> {val map = mutableMapOf<Any, Any?>()map["code"] = codemap["record"] = recordmap["totalFileSize"] = totalFileSizemap["pageList"] = pageList?.map { fileInfo ->mapOf("file_url" to fileInfo.file_url,"file_signature" to fileInfo.file_signature,"file_name" to fileInfo.file_name,"file_id" to fileInfo.file_id,"dev_model" to fileInfo.dev_model,"file_size" to fileInfo.file_size,"type" to fileInfo.type,"dev_type_id" to fileInfo.dev_type_id,"record_id" to fileInfo.record_id,"sn" to fileInfo.sn,"update_time_stamp" to fileInfo.update_time_stamp,"block_flag" to fileInfo.block_flag)}return map}override fun onError(type: ErrorNetType) {super.onError(type)// 处理错误情况// val result: Result<Map<Any, Any?>> = Result.success(//   mapOf(//     "name" to "John",//     "age" to 30,//     "email" to "john@example.com"//   )// )// callback(result)// 通过callback返回错误信息val failureResult: Result<Map<Any, Any?>> = Result.failure(Exception("An error occurred"))callback(failureResult)}override fun onFinish() {super.onFinish()}})}override fun disablePopRecognizer(disable: Boolean) {}}}

在flutter中统一使用这个类来获取原生获取的网络数据:

/// 成功回调
typedef SuccessCallback = void Function(Map<String, dynamic>? resultData, String resultCode, String resultMsg);/// 失败回调
typedef ErrorCallback = void Function();class RequireNativeApi {static void postWithPathOversea(String? url, Map<String?, Object?>? arguments,SuccessCallback? successCallback, ErrorCallback? errorCallback,{bool showToast = true}) {postWithPath(url, arguments, successCallback, errorCallback,showToast: showToast, appType: AppType.oversea);}static void postWithPathDomestic(String? url,Map<String?, Object?>? arguments,SuccessCallback? successCallback,ErrorCallback? errorCallback,{bool showToast = true}) {postWithPath(url, arguments, successCallback, errorCallback,showToast: showToast, appType: AppType.domestic);}static void postWithPath(String? url, Map<String?, Object?>? arguments,SuccessCallback? successCallback, ErrorCallback? errorCallback,{bool showToast = true, AppType appType = AppType.oversea}) {ApiParams apiParams = ApiParams();apiParams.url = url;apiParams.arguments = arguments;sgApi.requestNativeApi(apiParams).then((data) {debugPrint("");debugPrint("======================================================");debugPrint("api: $url");debugPrint("业务入参: $arguments");debugPrint("出参:$data");debugPrint("======================================================");if (data == null || data.isEmpty) {/// 网络异常if (showToast) {sgApi.showToast(appType, SGi18n.key("I18N_COMMON_NETWORK_ERROR"));}if (errorCallback != null) {errorCallback();}return;}var jsonData = json.decode(data);if (successCallback != null) {// 返回接口返回数据,需要调用各个实体类的方法,所以需要各个业务层将Map转为对应的实体类successCallback(jsonData['result_data'] ?? {},jsonData['result_code'] ?? "",jsonData['result_msg'] ?? "",);}}).onError((error, stackTrace) {debugPrint("RequireNativeApi error: $error");debugPrint("RequireNativeApi error: $stackTrace");if (showToast) {sgApi.showToast(appType, SGi18n.key("I18N_COMMON_NETWORK_ERROR_MESSAGE"));}if (errorCallback != null) {errorCallback();}});}
}

flutter中要使用的地方直接拿到成功和失败的回调即可:

RequireNativeApi.postWithPathOversea(Api.getDeleteUserMessage, argument,getDeleteMessageSuccess, () => SGOSLoadingToast.dismissLoading());

我项目中用的是getx,大家可以看看我完整的代码:

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:isolarcloud_flutter/api/api.dart';
import 'package:isolarcloud_flutter/api/require_native_api.dart';
import 'package:isolarcloud_flutter/bean/home_msg_entity.dart';
import 'package:isolarcloud_flutter/bean/update_msg_entity.dart';
import 'package:isolarcloud_flutter/modules/demo/constant/constant_state_id.dart';
import 'package:isolarcloud_flutter/utils/hud/sg_os_loading_toast.dart';
import 'package:isolarcloud_flutter/utils/json_cache_util.dart';import 'sg_message_first_state.dart';class SGMessageHomePageLogic extends GetxController {final SGMessageHomePageState state = SGMessageHomePageState();static const idMessageClearUpdate = "message_clear_update";static const idMessageList = "message_list";static const idLoadFail = "message_load_fail";void getList(String labelStr, {bool isFirst = false}) async {state.labelStr = labelStr;isFirst ? SGOSLoadingToast.showLoading() : null;Map<String, Object> argument = {};var cache = await JsonCacheManageUtils.getCacheData(JsonCacheManageUtils.HomeMessageResponse,labelId: labelStr.toString()).then((value) {if (value != null) {return HomeMsgEntity.fromJson(value as Map<String, dynamic>);}});state.hasCache = false;if (cache is HomeMsgEntity) {state.pageList = cache;state.hasCache = true;update([idMessageList + labelStr.toString()]);}RequireNativeApi.postWithPathOversea(Api.getHomeMessageList, argument, getHomeMessageSuccess, () {isFirst ? SGOSLoadingToast.dismissLoading() : null;update([idLoadFail]);});}void getHomeMessageSuccess(Map<String, dynamic>? resultData, String resultCode, String resultMsg) {if (resultCode == "1" && resultData != null && resultData.isNotEmpty) {JsonCacheManageUtils.saveCacheData(JsonCacheManageUtils.HomeMessageResponse,labelId: state.labelStr,resultData);state.pageList = HomeMsgEntity.fromJson(resultData);}SGOSLoadingToast.dismissLoading();if (!state.hasCache) {update(["$idMessageList${state.labelStr}"]);}}/// clear 消息 传null为全部void updateUserAllMessage(dynamic messageSceneCode) {SGOSLoadingToast.showLoading();Map<String, dynamic> argument = {"is_all": 1,"message_scene_code": messageSceneCode,};RequireNativeApi.postWithPathOversea(Api.getUpdateUserMessage, argument,getClearMessageSuccess, () => SGOSLoadingToast.dismissLoading());}void getClearMessageSuccess(Map<String, dynamic>? resultData, String resultCode, String resultMsg) {if (resultCode == "1" && resultData != null && resultData.isNotEmpty) {state.updateBean = UpdateMsgEntity.fromJson(resultData);}SGOSLoadingToast.dismissLoading();update([idMessageClearUpdate]);}//删除单个消息大类void deleteUserMessage(String? ids, String? messageSceneCode, int index) {SGOSLoadingToast.showLoading();Map<String, dynamic> argument = {"ids": ids,"message_scene_code": messageSceneCode,};state.removeIndex = index;RequireNativeApi.postWithPathOversea(Api.getDeleteUserMessage, argument,getDeleteMessageSuccess, () => SGOSLoadingToast.dismissLoading());}void getDeleteMessageSuccess(Map<String, dynamic>? resultData, String resultCode, String resultMsg) {debugPrint("resultData: $resultData");if (resultCode == "1" && resultData != null && resultData.isNotEmpty) {state.deleteBean = UpdateMsgEntity.fromJson(resultData);}SGOSLoadingToast.dismissLoading();update([StateListenerId.messageDelete]);}///底部按钮删除全部选中的void deleteCheckMessage(List<HomeMsgPageList> messageHomeList) {SGOSLoadingToast.showLoading();StringBuffer messageSceneCodes = StringBuffer();for (int i = 0; i < messageHomeList.length; i++) {String? sceneCode = messageHomeList[i].messageSceneCode;messageSceneCodes.write(sceneCode);if (i != messageHomeList.length - 1) {messageSceneCodes.write(',');}}String result = messageSceneCodes.toString();if (result.isEmpty) {return;}Map<String, dynamic> argument = {"ids": null,"message_scene_code": result,};RequireNativeApi.postWithPathOversea(Api.getDeleteUserMessage, argument,getDeleteMessageSuccess, () => SGOSLoadingToast.dismissLoading());}
}

按理来说这个GetxController类是用来访问网络的类,这里用来和原生交互,就这样子。

最近工作忙,加班重,疏于思考,缺乏输出,望大家理解,有时间优化文章,敬请期待!

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

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

相关文章

Netty入门学习和技术实践

Netty入门学习和技术实践 Netty1.Netty简介2.IO模型3.Netty框架介绍4. Netty实战项目学习5. Netty实际应用场景6.扩展 Netty 1.Netty简介 Netty是由JBOSS提供的一个java开源框架&#xff0c;现为 Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具&…

高精度地图定位在高速公路自动驾驶系统中的应用

近年来随着汽车保有量不断增加&#xff0c;随之而来的是: ( 1) 严重的交通拥堵&#xff0c;通行效率低下&#xff0c;用在通行上的时间不断增加; ( 2) 交通事故频发&#xff0c;交通事故导致的伤亡人数和费用不断增加&#xff0c;而且绝大多数事故是由人为因素导致的; ( 3) 大气…

Linux:Nginx服务与搭建

目录 一、Nginx概述 二、Nginx三大作用&#xff1a;反向代理、负载均衡、动静分离 三、Nginx和Apache 3.1Nginx和Apache的差异 3.2Nginx和Apache的优缺点比较 四、编译安装niginx 五、创建Nginx 自启动文件 六、Nginx的信号使用 6.1信号 七、升级 nginx1.18 nginx1.2…

企业展示小程序的制作流程及关键步骤详解

在移动互联网时代&#xff0c;企业展示小程序已成为各个行业推广和展示的重要工具。搭建一个企业展示小程序不仅能够提高企业形象&#xff0c;还能够增加用户粘性和提升用户体验。下面我们来看一下如何从零基础搭建一个企业展示小程序&#xff0c;并顺利上线。 第一步&#xff…

2023.8 - java - 多态

多态是同一个行为具有多个不同表现形式或形态的能力。 多态就是同一个接口&#xff0c;使用不同的实例而执行不同操作&#xff0c; 多态的优点 1. 可替换性2 可扩充性3. 接口性、灵活性、简化性4. 消除类型之间的耦合关系 多态存在的三个必要条件 继承重写父类引用指向子类…

【负载均衡】Nacos简单入门

Nacos简单入门 快速安装 在Nacos的GitHub页面&#xff0c;提供有下载链接&#xff0c;可以下载编译好的Nacos服务端或者源代码&#xff1a; 下载完压缩包之后&#xff0c;放在任意目录下面进行解压&#xff1a; GitHub主页&#xff1a;https://github.com/alibaba/nacos G…

机器学习策略——优化深度学习系统

正交化&#xff08;Orthogonalization&#xff09; 老式电视机&#xff0c;有很多旋钮可以用来调整图像的各种性质&#xff0c;对于这些旧式电视&#xff0c;可能有一个旋钮用来调图像垂直方向的高度&#xff0c;另外有一个旋钮用来调图像宽度&#xff0c;也许还有一个旋钮用来…

AIGC ChatGPT 按年份进行动态选择的动态图表

动态可视化分析的好处与优势&#xff1a; 1. 提高信息理解性&#xff1a;可视化分析使得大量复杂的数据变得易于理解&#xff0c;通过图表、颜色、形状、尺寸等方式&#xff0c;能够直观地表现不同的数据关系和模式。 2. 加快决策速度&#xff1a;数据可视化可以帮助用户更快…

RV64函数调用流程分析

RV64函数调用流程分析 1 RV64 函数调用实例2 对应代码的分析2.1 main函数及其对应的汇编程序2.1.1 main的C代码实现2.1.2 main函数对应汇编及其分析2.1.3 执行完成之后栈的存放情况 2.2 test_fun_a函数及其对应的汇编程序2.2.1 test_fun_a函数的C实现2.2.2 test_fun_a函数对应汇…

Flask狼书笔记 | 04_表单

文章目录 4 表单4.1 HTML表单4.2 使用Flask-WTF4.3 处理表单数据4.4 表单进阶实践小记 4 表单 表单是和用户交互最常见的方式之一&#xff0c;本章涉及的Python包由WTForms、Flask-WTF、Flask-CKEditor。&#xff08;p104&#xff09; 4.1 HTML表单 通过<form>标签创建…

2023国赛数学建模E题思路模型代码 高教社杯

本次比赛我们将会全程更新思路模型及代码&#xff0c;大家查看文末名片获取 之前国赛相关的资料和助攻可以查看 2022数学建模国赛C题思路分析_2022国赛c题matlab_UST数模社_的博客-CSDN博客 2022国赛数学建模A题B题C题D题资料思路汇总 高教社杯_2022国赛c题matlab_UST数模社…

【C/C++】父类指针指向子类对象 | 隐藏

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

ICCV 2023 Oral | 从无约束图像集合中生成新视角的交叉光线神经辐射场

文章链接&#xff1a;https://arxiv.org/abs/2307.08093 代码链接&#xff1a;https://github.com/YifYang993/CR-NeRF-PyTorch.git 01. 介绍 本工作旨在通过从不受限制的图像集合&#xff08;例如从互联网中爬取的图像&#xff09;中合成新视角图片&#xff0c;从而提供3D沉浸…

5.网络原理之初识

文章目录 1.网络发展史1.1独立模式1.2网络互连1.3局域网LAN1.3.1基于网线直连1.3.2基于集线器组建1.3.3基于交换机组建1.3.4基于交换机和路由器组建1.3.4.1路由器和交换机区别 1.4广域网WAN 2.网络通信基础2.1IP地址2.2端口号2.3认识协议2.4五元组2.5 协议分层2.5.1 分层的作用…

DTC状态变化例子 4

例子1&#xff1a; 此示例概述了两个操作周期排放相关的 OBD DTC 中 DTC 状态位的操作。该图显示了两个操作周期排放相关的 OBD DTC 的处理。该处理也可应用于非排放相关的 OBD DTC&#xff0c;此处显示仅供一般参考。 0 接收到清除诊断信息 → DTC 状态字节初始化。 1, 2 相关…

(动态规划) 剑指 Offer 48. 最长不含重复字符的子字符串 ——【Leetcode每日一题】

❓剑指 Offer 48. 最长不含重复字符的子字符串 难度&#xff1a;中等 请从字符串中找出一个最长的不包含重复字符的子字符串&#xff0c;计算该最长子字符串的长度。 示例 1: 输入: “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为…

JVM7:垃圾回收是什么?从运行时数据区看垃圾回收到底回收哪块区域?垃圾回收如何去回收?垃圾回收策略,引用计数算法及循环引用问题,可达性分析算法

垃圾回收是什么&#xff1f;从运行时数据区看垃圾回收到底回收哪块区域&#xff1f; 垃圾回收如何去回收&#xff1f; 垃圾回收策略 引用计数算法及循环引用问题 可达性分析算法 垃圾回收是什么&#xff1f;从运行时数据区看垃圾回收到底回收哪块区域&#xff1f;垃圾回收如何去…

ctfshow web入门 web103-web107

1.web103 和102一样 payload: v2115044383959474e6864434171594473&v3php://filter/writeconvert.base64-decode/resource1.php post v1hex2bin2.web104 值只要一样就可以了 payload: v21 post v113.web105 考查的是$$变量覆盖,die可以带出数据,输出一条消息&#xf…

C# winform加载yolov8模型测试(附例程)

第一步&#xff1a;在NuGet中下载Yolov8.Net 第二步&#xff1a;引用 using Yolov8Net; 第三步&#xff1a;加载模型 private IPredictor yolov8 YoloV8Predictor.Create("D:\\0MyWork\\Learn\\vs2022\\yolov_onnx\\best.onnx", mylabel); 第四步&#xff1a;图…