
正文
flutter怎么采集数据,flutter showsearch
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
Flutter入门(二)——实现一个简单的demo页面
首先查看入口函数:
类MyApp:
MyHomePage:
state:
build:
此demo页面涉及到两个组件:图片和icon。在这里做一个简单的介绍,更详细的学习请参考flutter官网和相关书籍
在flutter中,我们可以通过Image组件来加载并显示图片,Image的数据源可以是asset、文件、内存以及网络。
ImageProvider 是一个抽象类,主要定义了图片数据获取的接口 load() ,从不同的数据源获取图片需要实现不同的 ImageProvider ,如 AssetImage 是实现了从Asset中加载图片的ImageProvider,而 NetworkImage 实现了从网络加载图片的ImageProvider。
Image也提供了一个快捷的构造函数 Image.asset 用于从asset中加载、显示图片:
Image也提供了一个快捷的构造函数 Image.network 用于从网络加载、显示图片:
Flutter中,可以像web开发一样使用iconfont,iconfont也即"字体图标",它是将图标做成字体文件,然后通过指定不同的字符而显示不同的图片。
加号为图片组件,减一为icon组件。点击加号,数字加1;点击-1,数字减少1。
相关问答
Q1: Flutter与原生通信概述
flutter与原生通信主要有三种方式:MethodChannel、EventChannel、BasicMessageChannel,这三种方式均各有适用的场景:MethodChannel用于native与flutter的方法调用,EventChannel用于native单向的向flutter发送广播消息,BasicMessageChannel用于native与flutter之间的消息互发。
MethodChannel用于双方之间的方法互调,使用步骤是:
1.创建一个MethodChannel对象,传入MethodChannel名称。
2.使用setMethodHandle对对方调用自己的方法进行监听,通过回调中的MethodCall对象方法名判断、获取方法参数,并且返回调用结果。
3.使用invokeMethod来调用对方的方法,可传入方法名,方法参数,以及监听对方的回调结果。
以下是示例:
需要注意的是,MethodChannel的名称需要双方保持一致,否则就不是同一个MethodChannel了。另外这里的方法调用并不是像Java里面反射那样去先找到class示例对象再解析到相应的方法,而是将双方互发的消息包装成了MethodCall对象,拿到这个对象后通过MethodCall里面的方法名去判断要做什么操作,并不是直接就调用了自身(native或flutter)相对应的方法。具体要做什么操作、调用什么方法还是得自己去调用和实现。
EventChannel适用于native向flutter发送广播消息,只是单向的消息发送,native发,flutter收,返过来flutter并不能向native发送消息。例如native可将定位数据不断的报给flutter,或者录像数据等等,所有基于原生能力产生的数据都可以通过EventChannel进行发送。
步骤:
1.创建一个EventChannel对象,传入EventChannel名称。
2.flutter端调用receiveBroadcastStream进行广播消息注册,传入arguments参数即为广播名称,此参数是告诉native端你要接受的广播类型,判别是什么广播发送的数据。
2.native调用setStreamHandler方法进行广播消息监听,onListen回调里会有一个arguments参数,这里及为flutter注册的广播类型,若flutter端没有注册,则native端不会收到这个回调,也就无法进行消息发送。收到flutter端的广播注册后,根据arguments可判断广播类型,然后根据EventChannel.EventSink来进行消息发送,EventSink.success()即可将消息发送给flutter端。
3.flutter进行广播注册会返回一个streamSubscription类型的对象,该对象可以进行消息的停止,native可在onCancel回调里面收到。
示例如下:
BasicMessageChannel就是比较常用的消息互发,使用步骤如下:
1.创建BasicMessageChannel对象,传入BasicMessageChannel名称。还需传入编解码方式(可以自己实现),系统提供了一些列的编解码方式,后续会介绍到。
2.使用setMessageHandler方法进行消息监听,也可进行回复。
3.使用send方法进行消息发送。
无论哪种方式的消息传递,最终都是将自定义数据转化为二进制数据进行传递,flutter提供的编解码方式分为MethodCodec和MessageCodec两种,EventChannel和MethodChannel使用的就是MethodCodec,BasicMessageChannel使用的是MessageCodec。MethodCodec其实就是在MessageCodec的基础上将数据包装了一下,使其转化为MethodCall对象方便使用。
MethodCodec源码:
MethodCodec提供了两种方式:JSONMethodCodec和StandardMethodCodec,前一种就是JSON和MethodCall对象之间的互转,后一种则是根据传入的数据基本类型(String,Integer等)来进行互转。
MessageCodec则提供了四种方式,如下图,具体就不详细讲述了,看看名字就知道是怎么回事,可以直接去看源码。最常用和默认的就是StandardMessageCodec方式。
从上面的使用方式可以看出,每一种Channel在创建的时候都需要传递一个BinaryMessenger,这个接口可以在FlutterEngine里面拿到,因此需要在FlutterActivity里面实现configFlutterEngine方法里面重写这个方法。FlutterActivity在attach FlutterEngine之后就会调用这个configFlutterEngine方法,通过flutterEngine.getPlugins().add(FlutterPlugin)方法可以FlutterPlugin的回调方法里进行数据的初始化和销毁工作。如下图
这个回调方法里的FlutterPluginBinding提供了一些我们可能会用到的对象,如下:
Q2: Flutter与Android通信的三种方式
一、 MethodChannel
主要是flutter端调用android方法。flutter调取android方法,也可以android主动跟flutter通信,但是这个只能是传递数据,不是调方法。MethodChannel的flutter调取android方法,我之前写过,可以查看如下链接,
Android主动跟flutter通信,如下
二、 BasicMessageChannel
它是可以双端通信的,flutter端可以给Android发送消息,Android也可以给Flutter发送消息。
三、EventChannel
只能是原生发送消息给Flutter端,例如监听手机电量变化,网络变化,传感器等。
打印结果如下:
总结一下:
MethodChannel 用于传递方法调用(method invocation),是flutter调取原生方法的,也可以原生主动传递数据给Flutter。
BasicMessageChannel 用于传递字符串和半结构化的信息。是两个端相互发送数据,接收数据的。
EventChannel 用于数据流(event streams)的通信。通长用于Nativie向flutter的通信,如:手机电量变化,网络连接变化,陀螺仪,传感器等;
tip:多种类型的通道混用可能会出现报错问题。
Q3: Flutter 之 WebSockets (三十一)
Http协议是无状态的,只能由客户端主动发起,服务端再被动响应,服务端无法向客户端主动推送内容,并且一旦服务器响应结束,链接就会断开所以无法进行实时通信。WebSocket协议正是为解决客户端与服务端实时通信而产生的技术,现在已经被主流浏览器支持。目前 Flutter也提供了专门的包来支持WebSocket协议。
web_socket_channel package 提供了我们需要连接到WebSocket服务器的工具。该package提供了一个 WebSocketChannel 允许我们既可以监听来自服务器的消息,又可以将消息发送到服务器的方法。
执行flutter pub get 命令,即可
1. 连接到WebSocket服务器
2. 监听来自服务器的消息
使用一个 StreamBuilder 来监听新消息, 并用一个Text来显示它们
工作原理
WebSocketChannel 提供了一个来自服务器的消息 Stream 。该 Stream 类是 dart:async 包中的一个基础类。它提供了一种方法来监听来自数据源的异步事件。与 Future 返回单个异步响应不同, Stream 类可以随着时间推移传递很多事件。该 StreamBuilder 组件将连接到一个 Stream , 并在每次收到消息时通知Flutter重新构建界面
3. 将数据发送到服务器
为了将数据发送到服务器,我们会add消息给WebSocketChannel提供的sink。
WebSocketChannel 提供了一个 StreamSink ,它将消息发给服务器
StreamSink 类提供了给数据源同步或异步添加事件的一般方法
4. 关闭WebSocket连接
思考:
假如我们想通过WebSocket传输二进制数据应该怎么做(比如要从服务器接收一张图片)?我们发现StreamBuilder和Stream都没有指定接收类型的参数,并且在创建WebSocket链接时也没有相应的配置,貌似没有什么办法……其实很简单,要接收二进制数据仍然使用StreamBuilder,因为WebSocket中所有发送的数据使用帧的形式发送,而帧是有固定格式,每一个帧的数据类型都可以通过Opcode字段指定,它可以指定当前帧是文本类型还是二进制类型(还有其它类型),所以客户端在收到帧时就已经知道了其数据类型,所以flutter完全可以在收到数据后解析出正确的类型,所以就无需开发者去关心,当服务器传输的数据是指定为二进制时,StreamBuilder的snapshot.data的类型就是Listint,是文本时,则为String。
Q4: Flutter 之 数据传递
InheritedWidget 是 Flutter 中的一个功能型 Widget,适用于在 Widget 树中共享数据的场景。
class CounterPage extends StatefulWidget {
CounterPage({Key ? key}) :super(key: key);
@override
_CounterPageState createState() =_CounterPageState();
}
//
class _CounterPageState extends State {
int count =0;
//3我们通过 InheritedCountContainer.of 方法找到它,获取计数状态 count 并展示:
void _incrementCounter() = setState(() {count++;});// 修改计数器
@override
Widget build(BuildContext context) {
//2我们使用 CountContainer 作为根节点,并用 0 初始化 count。
return CountContainer(
model:this,
increment: _incrementCounter,// 提供修改数据的方法
child:Counter()
);
}
}
/*1
* 首先,为了使用 InheritedWidget,我们定义了一个继承自它的新类 CountContainer。
* 然后,我们将计数器状态 count 属性放到 CountContainer 中,
* 并提供了一个 of 方法方便其子 Widget 在 Widget 树中找到它。
* 最后,我们重写了 updateShouldNotify 方法,这个方法会在 Flutter
* 判断 InheritedWidget 是否需要重建,从而通知下层观察者组件更新数据时被调用到。
* 在这里,我们直接判断 count 是否相等即可。
* */
class CountContainer extends InheritedWidget {
static CountContainer?of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType();
}
final _CounterPageState model;// 直接使用 MyHomePage 中的 State 获取数据
final Function()increment;
CountContainer({
Key ?key,
required this.model,
required this.increment,
required Widget child,
}):super(key: key, child: child);
@override
bool updateShouldNotify(CountContainer oldWidget) =model != oldWidget.model;
}
class Counter extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 获取 InheritedWidget 节点
CountContainer?state =CountContainer.of(context);
return Scaffold(
appBar:AppBar(
title:Text("InheritedWidget demo"),
),
body:Text(
'You have pushed the button this many times: ${state?.model.count}',// 关联数据读方法
),
floatingActionButton:FloatingActionButton(onPressed:state?.increment),// 关联数据修改方法
);
}
}
Notification 是 Flutter 中进行跨层数据共享的另一个重要的机制。如果说 InheritedWidget 的数据流动方式是从父 Widget 到子 Widget 逐层传递,那 Notificaiton 则恰恰相反,数据流动方式是从子 Widget 向上传递至父 Widget。这样的数据传递机制适用于子 Widget 状态变更,发送通知上报的场景。
class CustomNotification extends Notification {
CustomNotification(this.msg);
final String msg;
}
class CustomChild extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
//按钮点击时分发通知
onPressed: () =CustomNotification("Hi").dispatch(context),
child:Text("Fire Notification"),
);
}
}
class NotificationWidget extends StatefulWidget {
@override
StatecreateState()=_NotificationState();
}
class _NotificationState extends State {
String _msg ="通知:";
@override
Widget build(BuildContext context) {
//监听通知
return NotificationListener(
onNotification: ( notification) {
setState(() {_msg += notification.msg+" ";});
return true;
},
child:Column(
mainAxisAlignment:MainAxisAlignment.center,
children: [Text(_msg),CustomChild()],
)
);
}
}
无论是 InheritedWidget 还是 Notificaiton,它们的使用场景都需要依靠 Widget 树,也就意味着只能在有父子关系的 Widget 之间进行数据共享。但是,组件间数据传递还有一种常见场景:这些组件间不存在父子关系。这时,事件总线 EventBus 就登场了。
事件总线是在 Flutter 中实现跨组件通信的机制。它遵循发布 / 订阅模式,允许订阅者订阅事件,当发布者触发事件时,订阅者和发布者之间可以通过事件进行交互。发布者和订阅者之间无需有父子关系,甚至非 Widget 对象也可以发布 / 订阅。
// 所以在这里,我们传输数据的载体就选择了一个有字符串属性的自定义事件类 CustomEvent:
class CustomEvent {
String msg;
CustomEvent(this.msg);
}
// 建立公共的 event bus
EventBus eventBus =new EventBus();
/*
* 我们定义了一个全局的 eventBus 对象,并在第一个页面监听了 CustomEvent 事件,
* 一旦收到事件,就会刷新 UI。
* 需要注意的是,千万别忘了在 State 被销毁时清理掉事件注册,
* 否则你会发现 State 永远被 EventBus 持有着,无法释放,从而造成内存泄漏:
*
* */
class FirstPage extends StatefulWidget {
@override
StatecreateState()=_FirstPageState();
}
class _FirstPageState extends State {
String msg ="通知:";
late StreamSubscription subscription;
@override
void initState() {
//监听CustomEvent事件,刷新UI
subscription =eventBus.on().listen((event) {
print(event.msg);
setState(() {
msg += event.msg;
});
});
super.initState();
}
dispose() {
subscription.cancel();//State销毁时,清理注册
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar:AppBar(title:Text("First Page"),),
body:Text(msg),
floatingActionButton:FloatingActionButton(onPressed: ()=Navigator.push(context,MaterialPageRoute(builder: (context) =SecondPage()))),
);
}
}
//我们在第二个页面以按钮点击回调的方式,触发了 CustomEvent 事件:
class SecondPage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar:AppBar(title:Text("Second Page"),),
body:RaisedButton(
child:Text('Fire Event'),
// 触发CustomEvent事件
onPressed: ()=eventBus.fire(CustomEvent("hello"))
),
);
}
}
Q5: Flutter Channel底层原理分析
百度网盘flutter 见46-Flutter Channel
Flutter 提供三种Channel用作Flutter与iOS原生平台之间的数据传递
1.FlutterBasicMessageChannel: 用作频繁与原生交互
2.FlutterMethodChannel:用来调用方法,双向通讯
3.FlutterEventChannel:数据流通讯
三种Channel,都有以下成员变量
1.name: Channel 的唯一标识
在Flutter应用中,通常存在多个Platform Channel,使用name区分不同的Channel
2.messenger: 消息信使(BinaryMessenger)
负责Flutter与原生之间的相互通讯
[methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
}];
setMethodCallHandler方法,MethodCallHandler放在FlutterBinaryMessageHandler中
创建一个FlutterMethodChannel,通过 setMethodCallHandler来进行消息处理,最终会为FlutterMethodChannel绑定一个FlutterBinaryMessageHandler,并以FlutterMethodChannel的name作为key,保存在一个Map结构中
先创建 FlutterEngine-FlutterViewController-FlutterMethodChannel,
调用setMethodCallHandler方法时,会进入FlutterEngine的setMessageHandlerOnChannel:binaryMessageHandle:中,在进入PlatformMessageRouter中进行储存
flutter怎么采集数据的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于flutter showsearch、flutter怎么采集数据的信息别忘了在本站进行查找喔。







