Flutter 状态管理框架Get

状态管理框架 Get的使用

目录

状态管理框架 Get的使用

GetMaterialApp

路由的注册

路由的跳转

middlewares的使用

组件使用 defaultDialog bottomSheet snackbar

状态刷新有很多种方式

ValueBuilder

Obx 基础使用

是时候引入GetxController, 也是Get里面的常用的

GetX

优化控制器的使用 put

优化控制器的使用find

优化控制器的使用 懒加载lazyput

GetView

接下来GetConnect就是网络请求的使用

GetConnect

GetConnectStatemixin

GetConnectDio

切换主题

 多语言切换

常使用的Getx自带的API


不得不说,GetX使你的代码量减少了许多, 一个obs. 一个obx. 搞定你的数据监听刷新, 给你不一样的简洁。

GetMaterialApp

 return GetMaterialApp(title: 'Flutter Demo',getPages: MyRoutes.routes, //注册路由// initialRoute: MyHomePage.route,  //该属性, 设置有有问题, 在自定义转场动画的时候, 跳转的时候右边会黑屏 unknownRoute: MyRoutes.notFoundPage, //默认404的路由地址theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),useMaterial3: true,),home: const MyHomePage(),);

// initialRoute: MyHomePage.route,//该属性,在自定义转场动画的时候, 跳转的时候右边会黑屏

路由的注册

class MyRoutes {static List<GetPage> routes = [//正常注册GetPage(name: MySettingPage.route, page: () => const MySettingPage()),GetPage(name: MyHomePage.route, page: () => const MyHomePage(), children: [//children 这里可以注册子页面, 一级, 二级, 三级, 页面都可以GetPage(name: MyProductPage.route, page: () => const MyProductPage(), children: [GetPage(name: MyProductDetailPage.route, page: () => const MyProductDetailPage()),GetPage(name: MySettingPage.route, page: () => const MySettingPage()),GetPage(name: MySettingPage.routeID, page: () => const MySettingPage()),]), ]),];
}

路由的跳转

//使用路由String跳转, 这样写, 注册的时候 /MyProductPage 必须要在 MyHomePage 的children: [ 里面] 如上展示
Get.toNamed("/MyHomePage/MyProductPage");
Get.toNamed("/MyHomePage/MyProductPage/MySettingPage");
//直接跳转对应的页面
Get.to(const MyProductPage());
//使用路由跳转并传值
Get.toNamed("/MyHomePage/MyProductPage/MySettingPage?id==345");//返回上一个页面, 并传值, 接收参数的 var result = await Get.toNamed("/MyHomePage/MyProductPage/MySettingPage?id==345");
Get.back(result: {"success": true}),//特殊路由传值 需要定义路由: "/MySettingPage/:id";, 才能使用下方跳转传值
Get.toNamed("/MyHomePage/MyProductPage/MySettingPage/8910");//跳转后, 消除上页面的堆栈
Get.off(const MyProductDetailPage());
Get.offNamed(MyProductDetailPage.route);//跳转后, 消除所有的堆栈
Get.offAll(const MyProductDetailPage());
Get.offAllNamed(MyProductDetailPage.route);

middlewares的使用

一个类似拦截器的功能,可以传入多个,需要自定研究下优先级。

 GetPage(name: MyMinePage.route, page: () => const MyMinePage(), middlewares: [        MyRouteAuthMiddleware()]),
class MyRouteAuthMiddleware extends GetMiddleware {@overrideRouteSettings? redirect(String? route) {// 加入 AuthService 这里可以判断下用户是否登录,  如果true return super.的方法//否则去都登陆页面Future.delayed(const Duration(seconds: 1), () => Get.snackbar("提示", "请先登录APP"));return const RouteSettings(name: MyLoginPage.route);}
}

组件使用 defaultDialog bottomSheet snackbar

Get.snackbar
Get.bottomSheet
Get.defaultDialog
自行调用, 没有难度

状态刷新有很多种方式

ValueBuilder

爱了, 爱了, 直接导入头文件, 只刷新该作用域的.

ValueBuilder<List<String>?>(initialValue: const ["A", "B", "C"],builder: (value, updateFn) {return Column(children: [Text("List -> $value"),ElevatedButton(onPressed: () {List<String> newList = [...value!]; // 使用扩展运算符来创建列表的浅拷贝newList.add("${newList.length}");// newList.removeAt(1); // 移除索引为1的元素newList.shuffle();//元素随机updateFn(newList); // 使用新列表更新状态},child: const Text('ValueBuilder -> add'),)]);}),   

Obx 基础使用

比如在Widget, 声明一个属性, 使用的时候使用Obx(()=>{}) 包裹一下,然后在其他地方点击,修改count值就OK了, 因为增加了obs, 就成了, count.value++ 来修改值

//Int
RxInt count = 0.obs;
var count1 = 0.obs;
Obx(() => Column(children: [Text("int -> $count"),Text("int -> $count1"),
])//刷新
updateCount() {count.value++;count1.value++;}
在监听list. map. 枚举 的时候要注意, 一定要从新赋值才会刷新//刷新枚举void updateViewState(ViewState newValue) {  viewState.value = newValue; // 更新枚举值  }  
//刷新listupdateList() {list[0] = "BMW";list1[0] = "BMW"; 
}
//刷新Map
updateMap() {map["Audi"] = "BMW";map1["Audi"] = "BMW";
}
//刷新List中的Model
updateModels() {models[0] = GetXModels(name: "BMW");models1[0] = GetXModels(name: "BMW");}
//刷新Model
updateModel() {model.value = GetXModels(name: "BMW");model1.value = GetXModels(name: "BMW");
}
使用的地方一地个要加上Obx()

是时候引入GetxController, 也是Get里面的常用的

GetX<MyGetxController>

可以包裹引用Controller值的地方, 进行局部刷新, 还有声明周期的回调 推荐 ☆☆☆

//要创建控制器Controller
class MyPutController extends GetxController {}
//在widget的build方法中
final MyGetxController getxController = MyGetxController();
//使用例子ListTile(title: const Text("update list"),subtitle: GetX<MyGetxController>(init: getxController,initState: (_) {},builder: (_) {return Column(crossAxisAlignment: CrossAxisAlignment.start,children: [Text('我要买${getxController.list.toString()}'),Text('我要买${getxController.list1.toString()}'),],);},),onTap: () {//list, 要修改list里面的元素, 才会去更新UIgetxController.updateList();},
),

优化控制器的使用 put

//在Widget的build方法里面我们注册一个controller 推荐 ☆☆☆

final MyPutController countController = Get.put<MyPutController>(MyPutController());
在使用过程中使用Obx(())包裹即可, 
ListTile(title: const Text("update Count"),subtitle: Obx(() => Column(crossAxisAlignment: CrossAxisAlignment.start,children: [Text('count = ${countController.count.value}'),Text('count = ${countController.count1.value}'),],)),onTap: () {countController.updateCount();},
),

优化控制器的使用find

//在put过MyProductController()的Widget的build方法里面即二级页面, 三级页面....子页面

final MyProductController productController = Get.find<MyProductController>();
在使用过程中使用Obx(())包裹即可, 也可以使用GetX<MyProductController>build 也可以
ListTile(title: Text("传值 Get.arguments; = ${details.toString()} parameters == ${parameters.toString()}"),subtitle: Obx(() => Text(productController.myProductList.length.toString())),onTap: () {productController.addProduct(MyProduct(name: 'iPhone 16', description: 'APPle 设备', price: 8199));productController.addCount();}),

优化控制器的使用 懒加载lazyput

这里就要引出Binding的使用了

class MyGetLazyPutBinding implements Bindings {@overridevoid dependencies() {Get.lazyPut(() => MyGetLazyPutController());}
}
// MyGetLazyPutController 上面说的controller. 必须创建, 切继承GetxController
//注册路由的时候
GetPage(name: MyLazyPutPage.route, page: () => const MyLazyPutPage(),binding: MyGetLazyPutBinding()),
//在Widget页面的时候就,不用调用Getx.put的方法, 会自动Put
//直接去find找到该Controller
final MyGetLazyPutController getLazyPutController = Get.find<MyGetLazyPutController>();
//在使用过程中使用Obx(())包裹即可, 也可以使用GetX<MyProductController>build 也可以
//建议自己撸一遍代码, 会印象更加深刻

GetView

这个更加简单, 省略put, find 的步骤, 不过还是要一个Controller的

//创建Widget的时候,需要增加一个泛型
class MyGetViewPage extends GetView<MyGetLazyPutController> 
//上面的路由注册, 还是要注册一个Controller
GetPage(name: MyLazyPutPage.route, page: () => const MyLazyPutPage(),binding: MyGetLazyPutBinding()),
//在widget中, 就自带了controller的变量 ,可以翻看源码中
abstract class GetView<T> extends StatelessWidget {const GetView({Key? key}) : super(key: key);final String? tag = null;T get controller => GetInstance().find<T>(tag: tag)!;@overrideWidget build(BuildContext context);
}
//就会知道, 内部帮忙find_Controller

 

接下来GetConnect就是网络请求的使用

GetConnect

这里跟官网的不太一样, 官网我感觉有点麻烦, 创建那么多的文件, 其实就是请求层, 数据层, 页面布局划分就好了

//1.我们先继承GetConnect 设置下你的请求相关配置
//如: baseUrl headers 以及其他设置
class MyBaseHttp extends GetConnect {@overridevoid onInit() {httpClient.baseUrl = "xxxxxx";// 请求拦截httpClient.addRequestModifier<void>((request) {Map<String, String> headerMap = {"os-type": GetPlatform.isIOS ? "ios" : "android","timestamp": DateTime.now().microsecondsSinceEpoch.toString(),};request.headers.addAll(headerMap);return request;});// 响应拦截httpClient.addResponseModifier((request, response) {return response;});}
}
//2.然后继承 MyBaseHttp, 创建你的serviceController
class MyServiceController extends MyBaseHttp {//获取数据, 自定义数据Future<MyGetConnectModel> getContent() async {Response response = await get('/route/external_link.json'); //这里去请求的, 有post. put. 自己看下APIif (response.statusCode == 200) {debugPrint(response.bodyString);return MyGetConnectModel(userId: 1, id: 2, title: 'title', body: 'body');} else {debugPrint(response.bodyString);return MyGetConnectModel(userId: 1, id: 2, title: 'title', body: 'body');}}
}
//3.创建页面的controller
class MyGetConnectController extends GetxController {// 获取实例final MyServiceController serviceController = Get.find<MyServiceController>();// modellate MyGetConnectModel getConnectModel;//监听状态, 这里是一个枚举, 这里你也可以监听其他的,比如model的变化Rx<ViewState> viewState = ViewState.normal.obs;getData() async {updateViewState(ViewState.loading);getConnectModel = await serviceController.getContent();updateViewState(ViewState.normal);}void updateViewState(ViewState newValue) {  viewState.value = newValue; // 更新枚举值  }  
}
//4.注册
class MyGetContentBuinding extends Bindings {@overridevoid dependencies() {Get.lazyPut(() => MyGetConnectService());Get.lazyPut(() => MyGetConnectController());}
}
//路由binding
GetPage(name: MyGetContentPage.route, page: () => const MyGetContentPage(),binding: MyGetContentBuinding()),
//5.创建Widget,布局
方式1: class MyGetContentPage extends GetView<MyGetConnectController> {}
方式2: class MyHomePage extends StatelessWidget{
final controller = Get.find<MyGetConnectController>();}
//数据刷新
GetX<MyGetConnectController>(initState: (state) {controller.getData();
}, init: controller,
builder: ((_) {debugPrint("controller.viewState.value: ${controller.viewState.value}")switch (controller.viewState.value) {case ViewState.loading:return const Center(child: CircularProgressIndicator(),);default:return _buildListView(controller.getConnectModel);}
})),
或者
Obx(()=>)
更新值的时候, 需要 controller哟

GetConnectStatemixin

//跟上面基本一致, 这里说下不同点
//创建页面控制器的时候需要增加监听的类型数据
class MyGetConnectStateMixinController extends GetxController with StateMixin<List<MyGetConnectModel>> { }
//List<MyGetConnectModel>就是我要监听的数据类型
//创建页面方式
class MyGetConnectStateMixinPage extends GetView<MyGetConnectStateMixinController> {}
也可以使用find的方式找到该 MyGetConnectStateMixinController
然后通过controller.obx 进行监听处理, 有多种状态,final bool isLoading;final bool isError;final bool isSuccess;final bool isEmpty;final bool isLoadingMore;final String? errorMessage;
// 是在页面的MyGetConnectStateMixinController 控制器里面进行定义的.相关代码@overridevoid onInit() {fetchList(); //获取数据super.onInit();}// 拉取数据列表Future<void> fetchList() async {// 获取数据, 也可以处理好处理传过来,final Response response = await connectStateMixinService.getContent(); //通过find找到该控制器 connectStateMixinService, 是继承上面的MyBaseHttp的请求类控制器// 判断请求是否有错误if (response.hasError) {// 改变数据,传入错误状态,在ui中会处理这些错误//返回状态的定义// change(null, status: RxStatus.error(response.statusText));// change(null, status: RxStatus.empty());} else {// 成功,自定义数据,改变状态为成功List<MyGetConnectModel> dataList = [];for (var i = 0; i < 10; i++) {MyGetConnectModel getConnectModel = MyGetConnectModel(userId: 12312, id: 231231, title: "title", body: "body");dataList.add(getConnectModel);}change(dataList, status: RxStatus.success());}//页面布局Widget, 根据不同的状态, 可以写不同的结果
controller.obx((state) {return ListView.separated(itemCount: state!.length,itemBuilder: (context, index) {final MyGetConnectModel getConnectModel = state[index];return ListTile(onTap: () {},title: Text(getConnectModel.title),trailing: Text("\$${getConnectModel.body}"),);},separatorBuilder: (BuildContext context, int index) {return const Divider();},);},onError: (error) {return Center(child: Text(error.toString()),);},onLoading: const SizedBox(width: double.infinity,height: double.infinity,child: Column(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: [CircularProgressIndicator(),SizedBox(height: 10),Text("疯狂加载中...",style: TextStyle(color: Colors.blue, fontSize: 16),),],),),onEmpty: const Center(child: Text("没有数据"),),
));

GetConnectDio

需要自行导入Dio的框架
把上面的 GetConnect 部分中的请求部分, 更换为Dio请求, 然后使用Rx定义,监听的变量。

//在Widget中, 通过Obx, 或者GetX<MyGetConnectController> 去刷新数据即可
class MyGetConnectDioPage extends GetView<MyGetConnectDioController> 

切换主题

return Scaffold(appBar: AppBar(title: const Text("切换主题"),),body: Center(child: ElevatedButton(onPressed: () {Get.changeTheme(Get.isDarkMode ? ThemeData.light() : ThemeData.dark());},child: Text("是否黑色主题 -> ${Get.isDarkMode}"),)),);

 多语言切换

class MyTranslationService extends Translations {static Locale? get locale => Get.deviceLocale;static const fallbackLocale = Locale('en', 'US');@overrideMap<String, Map<String, String>> get keys => {'en_US': enUS,  'zh_Hans': zhHans,'zh_HK': zhHK,};
}
//enUS  zhHans zhHK 要去创建文件 如: 
const Map<String, String> zhHans = {'title': '这是标题','login': '登录用户 @name,邮箱账号 @email',
};GetMaterialApp下:locale: MyTranslationService.locale,fallbackLocale: MyTranslationService.fallbackLocale,translations: MyTranslationService(),
// 使用
Text("title -> ${'title'.tr}"),
Text("login -> ${'login'.trParams({'name': 'xxx', 'email': 'xxx@gmail.com'})}"),//使用tr. trParams 来处理多语言
//设置多语音
var locale = const Locale('zh', 'HK');
Get.updateLocale(locale);

常使用的Getx自带的API

Get.arguments//给出以前的路由名称
Get.previousRoute// 给出要访问的原始路由,例如,rawRoute.isFirst()
Get.rawRoute// 允许从GetObserver访问Rounting API。
Get.routing// 检查 snackbar 是否打开
Get.isSnackbarOpen// 检查 dialog 是否打开
Get.isDialogOpen// 检查 bottomsheet 是否打开
Get.isBottomSheetOpen// 删除一个路由。
Get.removeRoute()//反复返回,直到表达式返回真。
Get.until()// 转到下一条路由,并删除所有之前的路由,直到表达式返回true。
Get.offUntil()// 转到下一个命名的路由,并删除所有之前的路由,直到表达式返回true。
Get.offNamedUntil()//检查应用程序在哪个平台上运行。
GetPlatform.isAndroid
GetPlatform.isIOS
GetPlatform.isMacOS
GetPlatform.isWindows
GetPlatform.isLinux
GetPlatform.isFuchsia//检查设备类型
GetPlatform.isMobile
GetPlatform.isDesktop
//所有平台都是独立支持web的!
//你可以知道你是否在浏览器内运行。
//在Windows、iOS、OSX、Android等系统上。
GetPlatform.isWeb// 相当于.MediaQuery.of(context).size.height,
//但不可改变。
Get.height
Get.width// 提供当前上下文。
Get.context// 在你的代码中的任何地方,在前台提供 snackbar/dialog/bottomsheet 的上下文。
Get.contextOverlay// 注意:以下方法是对上下文的扩展。
// 因为在你的UI的任何地方都可以访问上下文,你可以在UI代码的任何地方使用它。// 如果你需要一个可改变的高度/宽度(如桌面或浏览器窗口可以缩放),你将需要使用上下文。
context.width
context.height// 让您可以定义一半的页面、三分之一的页面等。
// 对响应式应用很有用。
// 参数: dividedBy (double) 可选 - 默认值:1
// 参数: reducedBy (double) 可选 - 默认值:0。
context.heightTransformer()
context.widthTransformer()/// 类似于 MediaQuery.of(context).size。
context.mediaQuerySize()/// 类似于 MediaQuery.of(context).padding。
context.mediaQueryPadding()/// 类似于 MediaQuery.of(context).viewPadding。
context.mediaQueryViewPadding()/// 类似于 MediaQuery.of(context).viewInsets。
context.mediaQueryViewInsets()/// 类似于 MediaQuery.of(context).orientation;
context.orientation()///检查设备是否处于横向模式
context.isLandscape()///检查设备是否处于纵向模式。
context.isPortrait()///类似于MediaQuery.of(context).devicePixelRatio。
context.devicePixelRatio()///类似于MediaQuery.of(context).textScaleFactor。
context.textScaleFactor()///查询设备最短边。
context.mediaQueryShortestSide()///如果宽度大于800,则为真。
context.showNavbar()///如果最短边小于600p,则为真。
context.isPhone()///如果最短边大于600p,则为真。
context.isSmallTablet()///如果最短边大于720p,则为真。
context.isLargeTablet()///如果当前设备是平板电脑,则为真
context.isTablet()///根据页面大小返回一个值<T>。
///可以给值为:
///watch:如果最短边小于300
///mobile:如果最短边小于600
///tablet:如果最短边(shortestSide)小于1200
///desktop:如果宽度大于1200
context.responsiveValue<T>()

状态管理框架 Provider 和 Get 的Likes, 各有千秋

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

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

相关文章

远程IO控制器ZLAN6808-3 使用JSON定时下发执行DO通断

一.使用场景 对于数据采集控制点是按照线性分布的场景&#xff0c;比如智慧园区的路灯、桥梁、路灯、数字化工厂、停车场车位监测、智慧停车场、智能停车架、楼宇自动控制系统等场景&#xff0c;采用以太网/4G远程I0模块要比采用PLC节省更多的成本。远程IO控制器在很多场景中作…

【无人机设计与控制】基于Astar算法无人机路径规划,优化路径平滑

摘要 本文提出了一种基于A算法的无人机路径规划方法&#xff0c;并通过路径平滑优化提升路径的可行性和安全性。传统A算法在生成路径时&#xff0c;常因路径节点分布不规则导致路径不平滑&#xff0c;影响无人机的飞行效率和安全性。本文通过引入贝塞尔曲线对A*算法生成的路径…

【自动化测试之oracle数据库】MacOs如何安装oracle- client

操作系统为Mac OS&#xff0c;本地在pycharm上跑自动化脚本时&#xff0c;因为有操作oracle数据库的部分&#xff0c;所以需要安装oracle数据库的客户端&#xff0c;并install cx_oracle,本文主要介绍如何在macOS上完成安装&#xff0c;并在python自动化测试代码中配置&#xf…

哥德巴赫猜想渐行渐远

我现在的工作&#xff0c;表明经典分析可能出了问题&#xff0c;如此则连Vinogradov的三素数定理都不成立了&#xff0c;更别说基于L-函数方程的陈氏定理“12”了。事实上即使L-函数方程成立&#xff0c;由于我指出Siegel定理不成立&#xff0c;陈景润和张益唐的工作就不成立。…

使用Python和Matplotlib模拟3D海浪动画

使用Python和Matplotlib模拟3D海浪动画 在计算机图形学和动画领域&#xff0c;模拟逼真的海洋表面一直是一个具有挑战性的问题。本文将介绍如何使用Python的Matplotlib库和Gerstner波浪模型&#xff0c;创建一个动态的3D海浪动画。通过叠加多个波浪&#xff0c;我们可以生成复…

【Fargo】14: sockaddr_in 、 sockaddr 、sockaddr_storage 区别及转换

sockaddr_in 和 sockaddr struct recv_addr_; uv_ip4_addr(ip.c_str(), port, &recv_addr); 这里libuv用的是sockaddr_in ,mediasoup用的是sockaddr,二者有什么区别,可以直接转换么sockaddr 看起来更为通用 差异和特定的用途 在网络编程中,sockaddr_in 和 sockaddr 是…

HarmonyOS ArkTS与C++数据类型转换

1. HarmonyOS ArkTS与C数据类型转换 本文介绍了C与TS各自数据类型与互相之间的数据类型转换&#xff0c;在需要使用C模块时可以快速上手对各种数据类型进行转换。 1.1. 概述 HarmonyOS的主力开发语言是ArkTS&#xff0c;也提供了C语言的支持&#xff0c;对于一些能力&#xff…

react mackDowan 渲染文本,图片,视频

需要安装&#xff1a;react-markdown&#xff1b;remark-gfm "react-markdown": "^9.0.1", "remark-gfm": "^4.0.0", import { useEffect, useState } from react; import ReactMarkdown, { Components } from react-markdown;functio…

iOS_响应者链 Responder Chain

文章目录 简述Hit-Test 机制 &#xff08;找到最佳响应者&#xff09;响应者链 Responder chain应用获取当前View的控制器对象&#xff1a;手势穿透&#xff1a; 简述 传递链&#xff1a; 系统向离用户最近的view传递。 UIKit –> active app’s event queue –> window …

【设计模式系列】迭代器模式(七)

一、什么是迭代器模式 迭代器模式&#xff08;Iterator Pattern&#xff09;是一种行为型设计模式&#xff0c;它提供一种方法来顺序访问一个聚合对象中的各个元素&#xff0c;而不暴露其内部的表示。迭代器模式将集合的遍历过程封装在一个独立的迭代器对象中&#xff0c;这样…

纯GO语言开发RTSP流媒体服务器-RTSP推流直播、本地保存录像、录像回放、http-flv及hls协议分发

温馨提示&#xff1a;我们分享的文章是给需要的人&#xff0c;不需要的人请绕过&#xff0c;文明浏览&#xff0c;误恶语伤人&#xff01; 前言 在软件开发中遇到使用流媒体音视频的行业比较多&#xff0c;如安防监控系统、无人机巡逻视频上云处理、直播平台、教育与企业培训…

如何快速使用Cesium完成项目

要快速使用Cesium完成项目&#xff0c;可以按照以下步骤进行&#xff1a; 学习基础知识&#xff1a; 首先&#xff0c;了解Cesium的基本概念和功能。可以通过阅读Cesium的官方文档和一些入门教程来掌握基础知识。例如&#xff0c;可以参考“Cesium速成教程&#xff1a;一小时入…

代码随想录(十二)——图论

并查集 并查集主要有三个功能。 寻找根节点&#xff0c;函数&#xff1a;find(int u)&#xff0c;也就是判断这个节点的祖先节点是哪个将两个节点接入到同一个集合&#xff0c;函数&#xff1a;join(int u, int v)&#xff0c;将两个节点连在同一个根节点上判断两个节点是否在…

阿里云物联网的通信方式

阿里云物联网通信的两种方式&#xff0c;一个是物模型&#xff08;分为服务&#xff0c;事件&#xff0c;属性&#xff09;&#xff0c;一个是自定义topic&#xff08;要另外设置数据流转&#xff09; 1.使用产品内的功能定义&#xff0c;&#xff08;其实也就是Topic中定义好的…

新手逆向实战三部曲之三——通过进入关键call追码注册软件(进阶)

教程开始&#xff1a; 通过前两次的学习&#xff0c;是不是感觉逆向也蛮有意思的呢&#xff0c;感兴趣的同学可以先看看前二次的内容再继续向下学习 新手逆向实战三部曲之一 新手逆向实战三部曲之二 有了上次爆破的基础&#xff0c;这次便省力了许多&#xff0c;这次从载入开始…

STM32第15章 RCC-使用HSE/HSI配置时钟

时间:2024.10.21-10.23 参考资料: 《零死角玩转STM32》“RCC-使用HSE/HIS配置时钟”章节 TIPS: 从前面的历程中我们知道,程序在启动的时候会执行汇编文件,汇编文件里会调用System_Init(固件库编程的函数),它里面会把时钟初始化成72M,因此前面我们在用固件库写程序的…

数据结构:“小猫钓鱼游戏”

一&#xff1a;题目 栈和队列的综合应用&#xff1a;“小猫钓鱼”的游戏规则是&#xff1a;将一副扑克牌平均分成两份&#xff0c;每人拿一份。玩家甲先拿出手中的第一张扑克牌放在桌上&#xff0c;然后玩家乙也拿出手中的第一张扑克牌&#xff0c;并放在玩家甲刚打出的扑克牌的…

采用Excel作为可视化设计器的开源规则引擎 NopRule

决策树和决策矩阵是业务人员可以直观理解的复杂IF-ELSE逻辑表达形式&#xff0c;也是规则引擎中最常用、最有用的部分。常见的规则引擎如Drools虽然提供了更加丰富的功能特性集&#xff0c; 特别是所谓的RETE算法可以用于高效复用多次重复出现的表达式片段&#xff0c;但在实际…

SpringSecurity + Jwt权限校验,接口调用403 Forbidden问题排查与解决

问题背景&#xff1a;部分接口调用正常&#xff0c;部分接口调用报403Forbidden&#xff0c;postman不显示具体报错信息。 问题描述&#xff1a; 接口调用报错&#xff0c;经排查&#xff0c;权限校验认证通过&#xff0c;可以进入接口&#xff0c;但是在执行过程中&#xff0…

深入了解 Android 中的命名空间:`xmlns:tools` 和其他常见命名空间

在 Android 开发中&#xff0c;xmlns &#xff08;.xml的namespace&#xff09;命名空间是一个非常重要的概念。通过引入不同的命名空间&#xff0c;可以使用不同的属性来设计布局、设置工具属性或者支持自定义视图等。除了 xmlns:tools 以外&#xff0c;还有很多常见的命名空间…