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

Widget中的State-学习笔记

        Widget 有 StatelessWidget 和 StatefulWidget 两种类型。StatefulWidget 应对有交互、需要动态变化视觉效果的场景,而 StatelessWidget 则用于处理静态的、无状态的视图展示。StatefulWidget 的场景已经完全覆盖了 StatelessWidget,因此我们在构建界面时,往往会大量使用 StatefulWidget 来处理静态的视图展示需求,看起来似乎也没什么问题。

UI 编程范式

        要想理解 StatelessWidget 与 StatefulWidget 的使用场景,我们首先需要了解,在 Flutter 中,如何调整一个控件(Widget)的展示样式,即 UI 编程范式。

        如果你有过原生系统(Android、iOS)或原生 JavaScript 开发经验的话,应该知道视图开发是命令式的,需要精确地告诉操作系统或浏览器用何种方式去做事情。比如,如果我们想要变更界面的某个文案,则需要找到具体的文本控件并调用它的控件方法命令,才能完成文字变更。

        下述代码分别展示了在 Android、iOS 及原生 Javascript 中,如何将一个文本控件的展示文案更改为 Hello World:

        


// Android设置某文本控件展示文案为Hello World
TextView textView = (TextView) findViewById(R.id.txt);
textView.setText("Hello World");// iOS设置某文本控件展示文案为Hello World
UILabel *label = (UILabel *)[self.view viewWithTag:1234];
label.text = @"Hello World";// 原生JavaScript设置某文本控件展示文案为Hello World
document.querySelector("#demo").innerHTML = "Hello World!";

与此不同的是,Flutter 的视图开发是声明式的,其核心设计思想就是将视图和数据分离,这与 React 的设计思路完全一致。   

如果要实现同样的需求,则要稍微麻烦点:除了设计好 Widget 布局方案之外,还需要提前维护一套文案数据集,并为需要变化的 Widget 绑定数据集中的数据,使 Widget 根据这个数据集完成渲染。

但是,当需要变更界面的文案时,我们只要改变数据集中的文案数据,并通知 Flutter 框架触发 Widget 的重新渲染即可。这样一来,开发者将无需再精确关注 UI 编程中的各个过程细节,只要维护好数据集即可。比起命令式的视图开发方式需要挨个设置不同组件(Widget)的视觉属性,这种方式要便捷得多。

Introduction to widgets

(Introduction to widgets | Flutter)

        Flutter 小部件是使用从 React 中汲取灵感的现代框架构建的。 中心思想是使用小部件构建 UI。 小部件描述了它们的视图在给定当前配置和状态的情况下应该是什么样子。 当小部件的状态发生变化时,小部件会重建其描述,框架将其与之前的描述进行比较,以确定底层渲染树从一种状态转换到另一种状态所需的最小变化。

        最小的 Flutter 应用程序只需使用一个小部件调用 runApp() 函数:

        

import 'package:flutter/material.dart';void main() {runApp(const Center(child: Text('Hello World',textDirection: TextDirection.ltr,),));
}

         runApp() 函数获取给定的 Widget 并使其成为小部件树的根。 在此示例中,小部件树由两个小部件组成,中心小部件及其子部件文本小部件。 该框架强制根部件覆盖屏幕,这意味着文本“Hello, world”最终在屏幕上居中。 在这种情况下需要指定文本方向; 当使用 MaterialApp 小部件时,这会为您处理,如后文所示。

        在编写应用程序时,通常会编写新的小部件,这些小部件是 StatelessWidget 或 StatefulWidget 的子类,具体取决于您的小部件是否管理任何状态。 小部件的主要工作是实现 build() 函数,该函数根据其他较低级别的小部件来描述小部件。 该框架依次构建这些小部件,直到该过程在代表底层 RenderObject 的小部件中触底,该渲染对象计算并描述小部件的几何形状。

Basic widgets Introduction to widgets | Flutter

Flutter 自带了一套强大的基础 widgets,其中常用的有:

Text

文本小部件允许在应用程序中创建一系列样式文本。Text class - widgets library - Dart API (flutter.dev)

具有单一样式的一系列文本。 文本小部件显示一串具有单一样式的文本。 根据布局约束,字符串可能会跨多行显示,也可能全部显示在同一行上。

样式参数是可选的。 省略时,文本将使用最接近的封闭 DefaultTextStyle 的样式。 如果给定样式的 TextStyle.inherit 属性为 true(默认值),则给定样式将与最接近的封闭 DefaultTextStyle 合并。 这种合并行为很有用,例如,在使用默认字体系列和大小时将文本设为粗体。

此示例说明如何使用溢出设置为 TextOverflow.ellipsis 的文本小部件显示文本。

import 'package:flutter/material.dart';void main() {runApp(const Center(child: Text('Hello, David! How are you?',textAlign: TextAlign.center,overflow: TextOverflow.ellipsis,textDirection: TextDirection.ltr,style: TextStyle(fontWeight: FontWeight.bold),),));
}

import 'package:flutter/material.dart';void main() {runApp(const Center(child: Text('Hello, David! How are you How are you How are you How are you How are you How are you How are you?',textAlign: TextAlign.center,overflow: TextOverflow.ellipsis,textDirection: TextDirection.ltr,style: TextStyle(fontWeight: FontWeight.bold),),));
}

 使用 Text.rich 构造函数,Text 小部件可以显示具有不同样式的 TextSpans 的段落。 下面的示例显示“Hello beautiful world”,每个单词都有不同的样式。

void main() {runApp(const MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Sample App',theme: ThemeData(primarySwatch: Colors.blue),home: const RichTextDemo(),);}
}class RichTextDemo extends StatelessWidget {const RichTextDemo({super.key});@overrideWidget build(BuildContext context) {return Container(alignment: Alignment.center,child: const Text.rich(TextSpan(text: 'Hello\n',style: TextStyle(fontWeight: FontWeight.normal),children: <TextSpan>[TextSpan(text: 'beautiful\n',style: TextStyle(fontStyle: FontStyle.italic)),TextSpan(text: 'world', style: TextStyle(fontWeight: FontWeight.bold))]),),);}
}

 互动性

要使 Text 对触摸事件做出反应,请将其包装在带有 GestureDetector.onTap 处理程序的 GestureDetector 小部件中。

在 Material Design 应用程序中,请考虑改用 TextButton,或者如果这不合适,至少使用 InkWell 而不是 GestureDetector。

要使文本部分具有交互性,请使用 RichText 并将 TapGestureRecognizer 指定为文本相关部分的 TextSpan.recognizer。

选择

默认情况下无法选择文本。 要使文本可选择,可以用 SelectionArea 小部件包装子树。 要从选择中排除 SelectionArea 下的子树的一部分,也可以用 SelectionContainer.disabled 包裹子树的那一部分。

import 'package:flutter/material.dart';void main() {runApp(const MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});static const String _title = 'Flutter Code Sample';@overrideWidget build(BuildContext context) {return MaterialApp(title: _title,home: Scaffold(appBar: AppBar(title: const Text(_title),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: const <Widget>[Text('Selectable text'),SelectionContainer.disabled(child: Text('Non-selectable text')),Text('Selectable text'),],),),),);}
}

 

RichText,它使您可以更好地控制文本样式。

DefaultTextStyle,它设置文本小部件的默认样式。

SelectableRegion,它提供了选择系统的概览。

行、列

Basic Flutter layout concepts | Flutter

这些 flex 小部件可让您在水平(行)和垂直(列)方向上创建灵活的布局。 这些对象的设计基于网络的 flexbox 布局模型。

Row class

在水平数组中显示其子项的小部件。

要使子View展开以填充可用的水平空间,请将子View包裹在 Expanded 小部件中。

Row 小部件不会滚动(并且通常认为 Row 中的子项数量多于可用房间所容纳的数量是错误的)。 如果您有一排小部件并希望它们能够在空间不足的情况下滚动,请考虑使用 ListView。

有关垂直变体,请参阅列。

如果只有一个子View,请考虑使用“对齐”或“居中”来定位子View。

Row 和 Column 是包含和布置小部件的类。 Row 或 Column 内的小部件称为子级,Row 和 Column 称为父级。 Row 水平放置其小部件,Column 垂直放置其小部件。

以下示例显示行和列之间的差异。

1. 单击运行按钮。

2、代码中,将Row改为Column,再次运行。

import 'package:flutter/material.dart';void main() {runApp(const MyWidget());
}class MyWidget extends StatelessWidget {const MyWidget({super.key});static const String _title = 'Flutter Code Sample';@overrideWidget build(BuildContext context) {return MaterialApp(title: _title,home: Scaffold(appBar: AppBar(title: const Text(_title),),body: Row(children: const [BlueBox(), BlueBox(), BlueBox()],),),);}
}class BlueBox extends StatelessWidget {const BlueBox({super.key});@overrideWidget build(BuildContext context) {return Container(width: 50,height: 50,decoration: BoxDecoration(color: Colors.blue, border: Border.all()),);}
}

 

 轴尺寸和对齐方式

到目前为止,BlueBox 小部件已被压在一起(在 UI 输出的左侧或顶部)。 可以使用轴大小和对齐属性更改 BlueBox 小部件的间隔方式。

mainAxisSize 属性

Row和Column占据不同的主轴。 Row 的主轴是水平的,Column 的主轴是垂直的。 mainAxisSize 属性确定 Row 和 Column 在其主轴上可以占据多少空间。 mainAxisSize 属性有两个可能的值:

MainAxisSize.max

行和列占据了它们主轴上的所有空间。 如果他们的孩子的组合宽度小于他们的主轴上的总空间,他们的孩子会被安排额外的空间。

MainAxisSize.min

Row 和 Column 仅在其子项的主轴上占据足够的空间。 他们的孩子在没有额外空间的情况下布置在主轴的中间。

提示:MainAxisSize.max 是 mainAxisSize 属性的默认值。 如果未指定其他值,则使用默认值,如上例所示。

示例:修改轴大小

以下示例将 mainAxisSize 显式设置为其默认值 MainAxisSize.max。

1. 单击运行按钮。

2、将MainAxisSize.max修改为MainAxisSize.min,重新运行。

import 'package:flutter/material.dart';void main() {runApp(const MyWidget());
}class MyWidget extends StatelessWidget {const MyWidget({super.key});static const String _title = 'Flutter Code Sample';@overrideWidget build(BuildContext context) {return MaterialApp(title: _title,home: Scaffold(appBar: AppBar(title: const Text(_title),),body: Row(mainAxisSize: MainAxisSize.min,children: const [BlueBox(), BlueBox(), BlueBox()],),),);}
}class BlueBox extends StatelessWidget {const BlueBox({super.key});@overrideWidget build(BuildContext context) {return Container(width: 50,height: 50,decoration: BoxDecoration(color: Colors.blue, border: Border.all()),);}
}

 

mainAxisAlignment 属性

当 mainAxisSize 设置为 MainAxisSize.max 时,Row 和 Column 可能会为其子项布置额外的空间。 mainAxisAlignment 属性决定了 Row 和 Column 如何将它们的孩子放置在额外的空间中。 mainAxisAlignment 有六个可能的值:

MainAxisAlignment.start

将孩子定位在主轴的起点附近。(Left for Row, top for Column

MainAxisAlignment.end

将孩子定位在主轴的末端附近。(Right for Row, bottom for Column

MainAxisAlignment.center

将孩子定位在主轴的中间。

MainAxisAlignment.spaceBetween

在孩子之间平均分配额外的空间。

MainAxisAlignment.spaceEvenly

将多余的空间平均分配给子项之间以及子项前后。

MainAxisAlignment.spaceAround

类似于 MainAxisAlignment.spaceEvenly,但将第一个子节点之前和最后一个子节点之后的一半空间减少到子节点之间宽度的一半。

总结来说,命令式编程强调精确控制过程细节;而声明式编程强调通过意图输出结果整体。对应到 Flutter 中,意图是绑定了组件状态的 State,结果则是重新渲染后的组件。在 Widget 的生命周期内,应用到 State 中的任何更改都将强制 Widget 重新构建。

其中,对于组件完成创建后就无需变更的场景,状态的绑定是可选项。这里“可选”就区分出了 Widget 的两种类型,即:StatelessWidget 不带绑定状态,而 StatefulWidget 带绑定状态。当你所要构建的用户界面不随任何状态信息的变化而变化时,需要选择使用 StatelessWidget,反之则选用 StatefulWidget。前者一般用于静态内容的展示,而后者则用于存在交互反馈的内容呈现中。

接下来,介绍 StatelessWidget 和 StatefulWidget,从源码分析它们的区别,并总结一些关于 Widget 选型的基本原则。

StatelessWidget

在 Flutter 中,Widget 采用由父到子、自顶向下的方式进行构建,父 Widget 控制着子 Widget 的显示样式,其样式配置由父 Widget 在构建时提供。

用这种方式构建出的 Widget,有些(比如 Text、Container、Row、Column 等)在创建时,除了这些配置参数之外不依赖于任何其他信息,换句话说,它们一旦创建成功就不再关心、也不响应任何数据变化进行重绘。在 Flutter 中,这样的 Widget 被称为 StatelessWidget(无状态组件)。

这里有一张 StatelessWidget 的示意图,如下所示:

 

接下来,我以 Text 的部分源码为例,和你说明 StatelessWidget 的构建过程。


class Text extends StatelessWidget {     //构造方法及属性声明部分const Text(this.data, {Key key,this.textAlign,this.textDirection,//其他参数...}) : assert(data != null),textSpan = null,super(key: key);final String data;final TextAlign textAlign;final TextDirection textDirection;//其他属性...@overrideWidget build(BuildContext context) {...Widget result = RichText(//初始化配置...));...return result;}
}

 可以看到,在构造方法将其属性列表赋值后,build 方法随即将子组件 RichText 通过其属性列表(如文本 data、对齐方式 textAlign、文本展示方向 textDirection 等)初始化后返回,之后 Text 内部不再响应外部数据的变化。

那么,什么场景下应该使用 StatelessWidget 呢?

这里,我有一个简单的判断规则:父 Widget 是否能通过初始化参数完全控制其 UI 展示效果?如果能,那么我们就可以使用 StatelessWidget 来设计构造函数接口了。

准备了两个简单的小例子,来帮助你理解这个判断规则。

第一个小例子是,我需要创建一个自定义的弹窗控件,把使用 App 过程中出现的一些错误信息提示给用户。这个组件的父 Widget,能够完全在子 Widget 初始化时将组件所需要的样式信息和错误提示信息传递给它,也就意味着父 Widget 通过初始化参数就能完全控制其展示效果。所以,我可以采用继承 StatelessWidget 的方式,来进行组件自定义。

第二个小例子是,我需要定义一个计数器按钮,用户每次点击按钮后,按钮颜色都会随之加深。可以看到,这个组件的父 Widget 只能控制子 Widget 初始的样式展示效果,而无法控制在交互过程中发生的颜色变化。所以,我无法通过继承 StatelessWidget 的方式来自定义组件。那么,这个时候就轮到 StatefulWidget 出场了。

StatefulWidget

与 StatelessWidget 相对应的,有一些 Widget(比如 Image、Checkbox)的展示,除了父 Widget 初始化时传入的静态配置之外,还需要处理用户的交互(比如,用户点击按钮)或其内部数据的变化(比如,网络数据回包),并体现在 UI 上。

换句话说,这些 Widget 创建完成后,还需要关心和响应数据变化来进行重绘。在 Flutter 中,这一类 Widget 被称为 StatefulWidget(有状态组件)。这里有一张 StatefulWidget 的示意图,如下所示:

Widget 是不可变的,发生变化时需要销毁重建,所以谈不上状态。那么,这到底是怎么回事呢?

其实,StatefulWidget 是以 State 类代理 Widget 构建的设计方式实现的。接下来,我就以 Image 的部分源码为例,和你说明 StatefulWidget 的构建过程,来帮助你理解这个知识点。

和上面提到的 Text 一样,Image 类的构造函数会接收要被这个类使用的属性参数。然而,不同的是,Image 类并没有 build 方法来创建视图,而是通过 createState 方法创建了一个类型为 _ImageState 的 state 对象,然后由这个对象负责视图的构建。

这个 state 对象持有并处理了 Image 类中的状态变化,所以我就以 _imageInfo 属性为例来和你展开说明。

_imageInfo 属性用来给 Widget 加载真实的图片,一旦 State 对象通过 _handleImageChanged 方法监听到 _imageInfo 属性发生了变化,就会立即调用 _ImageState 类的 setState 方法通知 Flutter 框架:“我这儿的数据变啦,请使用更新后的 _imageInfo 数据重新加载图片!”。而,Flutter 框架则会标记视图状态,更新 UI。


class Image extends StatefulWidget {//构造方法及属性声明部分const Image({Key key,@required this.image,//其他参数}) : assert(image != null),super(key: key);final ImageProvider image;//其他属性...@override_ImageState createState() => _ImageState();...
}class _ImageState extends State<Image> {ImageInfo _imageInfo;//其他属性...void _handleImageChanged(ImageInfo imageInfo, bool synchronousCall) {setState(() {_imageInfo = imageInfo;});}...@overrideWidget build(BuildContext context) {final RawImage image = RawImage(image: _imageInfo?.image,//其他初始化配置...);return image;}...
}

可以看到,在这个例子中,Image 以一种动态的方式运行:监听变化,更新视图。与 StatelessWidget 通过父 Widget 完全控制 UI 展示不同,StatefulWidget 的父 Widget 仅定义了它的初始化状态,而其自身视图运行的状态则需要自己处理,并根据处理情况即时更新 UI 展示。

通过 StatelessWidget 与 StatefulWidget 的源码,理解了这两种类型的 Widget。这时,你可能会问,既然 StatefulWidget 不仅可以响应状态变化,又能展示静态 UI,那么 StatelessWidget 这种只能展示静态 UI 的 Widget,还有存在的必要吗?

Checkbox class

复选框

复选框本身不保持任何状态。 相反,当复选框的状态发生变化时,小部件会调用 onChanged 回调。 大多数使用复选框的小部件将监听 onChanged 回调并使用新值重建复选框以更新复选框的视觉外观。

import 'package:flutter/material.dart';void main() {runApp(const MyApp());
}class MyApp extends StatelessWidget {static const String _title = 'Flutter Code Sample';const MyApp({super.key});@overrideWidget build(BuildContext context) {return MaterialApp(title: _title,home: Scaffold(appBar: AppBar(title: const Text(_title),),body: const Center(child: MyStatefulWidget(),),),);}
}class MyStatefulWidget extends StatefulWidget {const MyStatefulWidget({super.key});@overrideState<StatefulWidget> createState() {return _MyStatefulWidgetState();}
}class _MyStatefulWidgetState extends State<MyStatefulWidget> {bool isChecked = false;@overrideWidget build(BuildContext context) {Color getColor(Set<MaterialState> states) {const Set<MaterialState> interactiveStates = <MaterialState>{MaterialState.pressed,MaterialState.hovered,MaterialState.focused};if (states.any(interactiveStates.contains)) {return Colors.blue;}return Colors.red;}return Checkbox(checkColor: Colors.white,fillColor:MaterialStateProperty.resolveWith((states) => getColor(states)),value: isChecked,onChanged: (bool? value) {setState(() {isChecked = value!;});},);}
}

 

 TextField class

import 'package:flutter/material.dart';void main() => runApp(const MyApp());class MyApp extends StatelessWidget {const MyApp({super.key});static const String _title = 'Flutter Code Sample';@overrideWidget build(BuildContext context) {return MaterialApp(title: _title,home: Scaffold(appBar: AppBar(title: const Text(_title),),body: const Center(child: MyStatefulWidget(),),),);}
}class MyStatefulWidget extends StatefulWidget {const MyStatefulWidget({super.key});@overrideState<StatefulWidget> createState() {return _MyStatefulWidgetState();}
}class _MyStatefulWidgetState extends State<MyStatefulWidget> {late TextEditingController _controller;@overridevoid initState() {super.initState();_controller = TextEditingController();}@overridevoid dispose() {_controller.dispose();super.dispose();}@overrideWidget build(BuildContext context) {return Scaffold(body: TextField(controller: _controller,onSubmitted: (String value) async {await showDialog(context: context,builder: (BuildContext context) {return AlertDialog(title: const Text("THanks"),content: Text('You typed "$value", which has length ${value.characters.length}.'),actions: <Widget>[TextButton(onPressed: () {Navigator.pop(context);},child: const Text("OK"))],);});},),);}
}

 

StatefulWidget 要慎用

对于 UI 框架而言,同样的展示效果一般可以通过多种控件实现。从定义来看,StatefulWidget 仿佛是万能的,替代 StatelessWidget 看起来合情合理。于是 StatefulWidget 的滥用,也容易因此变得顺理成章,难以避免。

但事实是,StatefulWidget 的滥用会直接影响 Flutter 应用的渲染性能。

看一下 Widget 的更新机制,完全使用 StatefulWidget 是有代价的:

Widget 是不可变的,更新则意味着销毁 + 重建(build)。StatelessWidget 是静态的,一旦创建则无需更新;而对于 StatefulWidget 来说,在 State 类中调用 setState 方法更新数据,会触发视图的销毁和重建,也将间接地触发其每个子 Widget 的销毁和重建。

如果我们的根布局是一个 StatefulWidget,在其 State 中每调用一次更新 UI,都将是一整个页面所有 Widget 的销毁和重建。

虽然 Flutter 内部通过 Element 层可以最大程度地降低对真实渲染视图的修改,提高渲染效率,而不是销毁整个 RenderObject 树重建。但,大量 Widget 对象的销毁重建是无法避免的。如果某个子 Widget 的重建涉及到一些耗时操作,那页面的渲染性能将会急剧下降。

正确评估你的视图展示需求,避免无谓的 StatefulWidget 使用,是提高 Flutter 应用渲染性能最简单也是最直接的手段。

由于 Widget 采用由父到子、自顶向下的方式进行构建,因此在自定义组件时,我们可以根据父 Widget 是否能通过初始化参数完全控制其 UI 展示效果的基本原则,来判断究竟是继承 StatelessWidget 还是 StatefulWidget。

尽管 Flutter 会通过 Element 层去最大程度降低对真实渲染视图的修改,但大量的 Widget 销毁重建无法避免,因此避免 StatefulWidget 的滥用,是最简单、直接地提升应用渲染性能的手段。需要注意的是,除了我们主动地通过 State 刷新 UI 之外,在一些特殊场景下,Widget 的 build 方法有可能会执行多次。因此,我们不应该在这个方法内部,放置太多有耗时的操作。

相关文章:

Widget中的State-学习笔记

Widget 有 StatelessWidget 和 StatefulWidget 两种类型。StatefulWidget 应对有交互、需要动态变化视觉效果的场景&#xff0c;而 StatelessWidget 则用于处理静态的、无状态的视图展示。StatefulWidget 的场景已经完全覆盖了 StatelessWidget&#xff0c;因此我们在构建界面时…...

股市实战技巧(知行合一)

投资策略 长线&#xff1a;优质核心股票大仓位核心标的票&#xff0c;小仓位短线投资投机小储蓄可加大投机仓位价值投资也要去做仓位控制 行情好&#xff0c;总体大仓位&#xff0c;行情小&#xff0c;小仓位个股根据走势调整个股仓位&#xff08;布林线的20%原则&#xff09;…...

k8s-资源限制-探针检查

文章目录一、资源限制1、资源限制的使用2、reuqest资源&#xff08;请求&#xff09;和limit资源&#xff08;约束&#xff09;3、Pod和容器的资源请求和限制4、官方文档示例5、资源限制实操5.1 编写yaml资源配置清单5.2 释放内存&#xff08;node节点&#xff0c;以node01为例…...

一文让你彻底了解Linux内核文件系统

一&#xff0c;文件系统特点 文件系统要有严格的组织形式&#xff0c;使得文件能够以块为单位进行存储。文件系统中也要有索引区&#xff0c;用来方便查找一个文件分成的多个块都存放在了什么位置。如果文件系统中有的文件是热点文件&#xff0c;近期经常被读取和写入&#xf…...

解决前端组件下拉框选择功能失效问题

问题&#xff1a; 页面下拉框选择功能失效 现象&#xff1a; 在下拉框有默认值的情况下&#xff0c;点击下拉框的其他值&#xff0c;发现并没有切换到其他值 但是在下拉框没默认值的情况下&#xff0c;功能就正常 原因 select 已经绑定选项&#xff08;有默认值&#xff09; 在…...

Linux_vim编辑器入门级详细教程

前言&#xff08;1&#xff09;vim编辑器其实本质上就是对文本进行编辑&#xff0c;比如在.c文件中改写程序&#xff0c;在.txt文件写笔记什么的。一般来说&#xff0c;我们可以在windows上对文本进行编译&#xff0c;然后上传给Linux。但是有时候我们可能只是对文本进行简单的…...

TCP 的演化史-TCP 是一个过渡

TCP 诞生于 1970 年代早期&#xff0c;彼时没有分组交换网的大规模应用&#xff0c;彼时绝大多数通信都在使用电话&#xff0c;电报&#xff0c;电挂等电路交换技术。 诞生在这种环境下的技术不可能脱离时代的影响&#xff0c;如果一个孩子出生在一个父母关系冷漠的家庭&#x…...

Flask

Flask第三方组件非常全&#xff0c;适合小型 API服务类项目&#xff0c;但第三方组件运行稳定性相对Django差。 基础知识 Flask安装 pip install flask2.0.3Flask库文件 Jinjia2&#xff1a;模板渲染库Markupsafe&#xff1a;返回安全标签 只要Flask返回模板或者标签时都会…...

SAP系统与MES系统的数据协同技术方案

1&#xff0e;MES介绍 本文中提到的MES系统是在西门子公司的SIMATIC IT平台上开发完成。所有的应用子系统进行统一分析、统一设计、统一开发&#xff0c;利用统一的开发平台和数据库系统&#xff0c;保证了管理系统的集成性、高效性。 2&#xff0e;数据协同接口包含的…...

2018年蓝桥杯省赛试题-5道(Python)

文章目录一、日志统计思考二、递增三元组思考三、螺旋折线思考四、乘积最大思考五、全球变暖思考尾声提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、日志统计 题目描述 小明维护着一个程序员论坛。 现在他收集了一份"点赞"日志&#xf…...

Python稀疏矩阵最小二乘法

文章目录最小二乘法返回值测试最小二乘法 scipy.sparse.linalg实现了两种稀疏矩阵最小二乘法lsqr和lsmr&#xff0c;前者是经典算法&#xff0c;后者来自斯坦福优化实验室&#xff0c;据称可以比lsqr更快收敛。 这两个函数可以求解AxbAxbAxb&#xff0c;或arg min⁡x∥Ax−b…...

mac本前端Homebrew下载,操作

1、打开电脑终端 2、下载Homebrew&#xff0c;在终端中输入 /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"开始下载Homebrew&#xff0c;因为这个地址是国外网站&#xff0c;下载失败的话&#xff0c;输入…...

Linux系统之查看进程监听端口方法

Linux系统之查看进程监听端口方法一、端口监听介绍二、使用netstat命令1.netstat命令介绍2.netstat帮助3.安装netstat工具4.列出所有监听 tcp 端口5.显示TCP端口的统计信息6.查看某个服务监听端口三、使用ss命令1.ss命令介绍2.ss命令帮助3.查看某个服务监听端口四、使用lsof命令…...

使用命令别名一键启动arthas

1. 使用命令别名启动arthas 确保单板上有jdk和arthas jdk目录&#xff1a;/home/xinliushijian/arthas/jdk arthas目录&#xff1b;/home/xinliushijian/arthas su xinliushijian编写脚本messi.sh cd /home/xinliushijian/arthas vi messi.sh 内容如下&#xff1a; #!/bin/ba…...

python+pytest接口自动化(2)-HTTP协议基础

HTTP协议简介HTTP 即 HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09;&#xff0c;是互联网上应用最为广泛的一种网络协议。所有的 WWW 文件都必须遵守这个标准。设计 HTTP 最初的目的是为了提供一种发布和接收 HTML 页面的方法。HTTP 协议在 OSI 模型中属…...

操作系统权限提升(十五)之绕过UAC提权-基于白名单DLL劫持绕过UAC提权

系列文章 操作系统权限提升(十二)之绕过UAC提权-Windows UAC概述 操作系统权限提升(十三)之绕过UAC提权-MSF和CS绕过UAC提权 操作系统权限提升(十四)之绕过UAC提权-基于白名单AutoElevate绕过UAC提权 注&#xff1a;阅读本编文章前&#xff0c;请先阅读系列文章&#xff0c;以…...

非常好看的html网页个人简历

一. 前言 文末获取gitee链接 在前几天逛b站的时候&#xff0c;发现了个比较实用的东西-----个人简介网页版&#xff0c;相当于网页版的个人简历&#xff0c;相较于PDF形式的&#xff0c;网页版所能呈现内容更加丰富&#xff0c;而且更加美观&#xff0c;在BOOS上被HR小姐姐要…...

轻量级网络模型ShuffleNet V2

在学习ShuffleNet V2内容前需要简单了解卷积神经网络和MobileNet,以及Shuffnet V1的相关内容&#xff0c;大家可以出门左转&#xff0c;去看我之前的几篇博客MobileNet发展脉络&#xff08;V1-V2-V3&#xff09;&#xff0c;轻量级网络模型ShuffleNet V1&#x1f197;&#xff…...

分享美容美发会员管理系统功能的特点_美容美发会员管理系统怎么做

人们越来越关心美发&#xff0c;美发行业发展迅速&#xff0c;小程序可以连接在线场景&#xff0c;许多美发院也开发了会员卡管理系统。那么一个实用的美发会员管理系统怎么制作呢&#xff1f;它有什么功能&#xff1f;我们一起来看看~&#xff08;干货满满&#xff0c;耐心看完…...

Oracle-05-DCL篇

🏆一、简介 Oracle的DCL代表数据库控制语言,用于管理数据库对象的访问和安全性。DCL的两个主要命令是GRANT和REVOKE。 GRANT命令用于授予用户或角色对数据库对象的访问权限,例如表、视图或存储过程。GRANT命令的语法如下: GRANT privilege_name [, privilege_name]... …...

tess4j简单使用入门

tess4j下载 下载地址: https://sourceforge.net/projects/tess4j/ 不要直接下载,点击files,然后下载最新版 下载解压后放到指定的目录即可,这里放到d:\jar目录下 tess4j根目录: d:\jar\tess4j tess4j使用 把test4j项目目录中dist和lib目录下的所有jar包导入到需要的项目中…...

WebGPU学习(4)---使用 UniformBuffer

接下来让我们使用 UniformBuffer。UniformBuffer 是一个只读内存区域&#xff0c;可以在着色器上访问。 这次&#xff0c;我们将传递给着色器的矩阵存储在 UniformBuffer 中。演示示例 1.在顶点着色器中的 UniformBuffer 这次我们在顶点着色器里定义一个名为Uniforms的新结构体…...

Http客户端Feign-远程调用

Feign的使用步骤 引入依赖添加EnableFeignClients注解编写FeignClient接口使用FeignClient中定义的方法代替RestTemplate Feign的日志配置 1.方式一是配置文件&#xff0c;feign.client.config.xxx.loggerLevel 如果xxx是default则代表全局如果xxx是服务名称,例如userservi…...

RK3568镜像的拆包和打包

文章目录 前言一、window上分包和打包分包打包二、Linux上分包和打包分包打包总结前言 本文记录在win10上利用瑞芯微提供的工具进行分包和打包,同样也有Linux教程 提示:以下是本篇文章正文内容,下面案例可供参考 一、window上分包和打包 分包 window下一般直接利用工具即…...

《设计模式》适配器模式

《设计模式》适配器模式 适配器&#xff08;Adapter&#xff09;是一种结构型设计模式&#xff0c;它允许我们将一个类的接口转换成另一个类的接口&#xff0c;从而使得原本由于接口不兼容而无法合作的类能够一起工作。适配器模式通常用于以下情况&#xff1a; 在已有的类中添…...

linux 随笔 5-服务管理

0. 装到虚拟机与物理机&#xff0c;感觉各有各的不方便 Linux下systemctl命令和service、chkconfig命令的区别 1. service 根据/etc/init.d目录下的配置&#xff0c;做服务相关的&#xff1a; 启动停止重新启动关闭系统服务 2. chkconfig 用于维护 /etc/rc[0-6].d 的命令…...

【java基础】枚举类(enum)

文章目录基本介绍快速使用字段、方法、构造器枚举类方法toString方法valueOf方法values方法ordinal方法基本介绍 在java中有一种特殊的类型就是枚举类&#xff0c;对于一个有限的有固定值的集合&#xff0c;我们就可以考虑使用枚举类来进行表示&#xff0c;例如服装的大小为 小…...

Linux2

&#xff08;1&#xff09;root用户的主目录&#xff1a; &#xff08;3&#xff09;查看 &#xff08;4&#xff09;远程登陆系统&#xff1a;CentOS7上使用ifconfig查看IP&#xff0c;使用putty远程登陆 &#xff08;5&#xff09;查询目前用户登录情况&#xff1a;who命令…...

C语言基础应用(二)数据的转换与输入输出

学习了C语言的基本数据类型后&#xff0c;我们可能会想这些数据如何进行运算&#xff0c;是否可以让不同类型的数据直接进行运算呢&#xff1f; 一、数据类型转换 1.1 int类型与float类型之间的转换 int i 5; // j值为2.000000 因为左右操作数均为整型float j i/2; // …...

C# 用NPOI读取EXCEL

1. 复制DLL文件 ICSharpCode.SharpZipLib.dll NPOI.dll NPOI.OOXML.dll NPOI.OpenXml4Net.dll NPOI.OpenXmlFormats.dll 2. 在工程中添加引用 3. using System.IO; using NPOI.HSSF.UserModel; using NPOI.XSSF.UserModel; using NPOI.SS.UserModel; using NPOI.OpenXml4Ne…...