Flutter 框架调研报告

针对flutter的项目暂时有Bloc、Mobx、scoped_model、fish_redux、Provider 五种框架,下面我们介绍一下:

提出疑问:

1.flutter是什么?

2.这些框架是解决什么问题的,为什么会需要这种框架?/响应式状态管理器/响应式编程是一种面向数据流和变化传播的编程范式

3.每个框架有什么优缺点?

4.我们应该使用什么框架比较好?

问题1:flutter是什么?

    Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作、跨平台运行。

问题2:这些框架是解决什么问题的?

    这些框架都是来一种状态管理框架。响应式的编程框架中都会有一个永恒的主题——“状态(State)管理”,无论是在React/Vue(两者都是支持响应式编程的Web开发框架)还是Flutter中,他们讨论的问题和解决的思想都是一致的。一般的原则是:如果状态是组件私有的,则应该由组件自己管理;如果状态要跨组件共享,则该状态应该由各个组件共同的父元素来管理。

问题3:每个框架都是怎么运行的?

框架一:scoped_model

一种最单纯的状态管理工具。

image

1.创建model

数据刷新需要调用 notifyListeners方法

import 'package:scoped_model/scoped_model.dart';

class CountModel extends Model{

int _count = 0;

get count => _count;

void increment(){

_count++;

notifyListeners();

}

CountModel of(context) =>

ScopedModel.*of*(context);//使用ScopedModel.of方式

}

第二步:放入顶层

import 'package:flutter/material.dart';

import 'package:scoped_demo/top_screen.dart';

import 'package:scoped_demo/model/count_model.dart';

import 'package:scoped_model/scoped_model.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {

//创建顶层状态

CountModel countModel = CountModel();

@override

Widget build(BuildContext context) {

return ScopedModel(

model: countModel,

child: new MaterialApp(

title: 'Flutter Demo',

theme: new ThemeData(

primarySwatch: Colors.*blue*,

),

home: TopScreen(),

),

);

}

}

第三步:页面使用

获取model分两种:

1. ScopedModelDescendant获取model

2.ScopedModel.of(context)

import 'package:flutter/material.dart';

import 'package:scoped_demo/model/count_model.dart';

import 'package:scoped_model/scoped_model.dart';

import 'package:scoped_demo/under_screen.dart';

class TopScreen extends StatefulWidget {

@override

_TopScreenState createState() => _TopScreenState();

}

class _TopScreenState extends State {

//静态获取model用法实例

Model getModel(BuildContext context){

//直接使用of

final countModel = ScopedModel.*of*(context);

//使用CountModel中重写的of

final countModel2 = CountModel().of(context);

countModel.increment();

countModel2.increment();

return countModel;

// return countMode2;

}

@override

Widget build(BuildContext context) {

return ScopedModelDescendant(

builder: (context,child,model){

return Scaffold(

appBar: AppBar(

title: Text('Top Screen'),

),

body: Center(

child: Text(

model.count.toString(),

style: TextStyle(fontSize: 48.0),

),

),

floatingActionButton: FloatingActionButton(

onPressed: () {

Navigator.*of*(context).push(MaterialPageRoute(builder: (BuildContext context){

return UnderScreen(title: "Under Screen",);

}));

},

child: Icon(Icons.*forward*),

),

);

},

);

}

}

框架二:Provider

第一步:创建数据 Model

import 'package:flutter/material.dart';

class CounterModel with ChangeNotifier {

int _count = 0;

int get value => _count;

void increment() {

_count++;

notifyListeners();

}

}

第二步:创建顶层共享数据

void main() {

final counter = CounterModel();

final textSize = 48;

runApp(

Provider.value(

value: textSize,

child: ChangeNotifierProvider.value(

value: counter,

child: MyApp(),

),

),

);

}

第三步:在子页面中获取状态(Provider.of)

class FirstScreen extends StatelessWidget {

@override

Widget build(BuildContext context) {

final _counter = Provider.of(context);

final textSize = Provider.of(context).toDouble();

return Scaffold(

appBar: AppBar(

title: Text('FirstPage'),

),

body: Center(

child: Text(

'Value: ${_counter.value}',

style: TextStyle(fontSize: textSize),

),

),

floatingActionButton: FloatingActionButton(

onPressed: () => Navigator.of(context)

.push(MaterialPageRoute(builder: (context) => SecondPage())),

child: Icon(Icons.navigate_next),

),

);

}

}

方法二:

class SecondPage extends StatelessWidget {

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text('Second Page'),

),

body: Consumer2(

builder: (context, CounterModel counter, int textSize, _) => Center(

child: Text(

'Value: ${counter.value}',

style: TextStyle(

fontSize: textSize.toDouble(),

),

),

),

),

floatingActionButton: Consumer(

builder: (context, CounterModel counter, child) => FloatingActionButton(

onPressed: counter.increment,

child: child,

),

child: Icon(Icons.add),

),

);

}

}

框架三:Bloc (https://pub.dev/packages/flutter_bloc

|

image

|

image

使用:

第一步,创建一个bloc:内部包含sink、stream

Sink作用:进行事件触发,进行业务处理获取数据流

Stream作用:数据监听,用于widget监听数据变化的Observable。

如下:

import 'dart:async';

class CountBLoC {

int _count = 0;

var _countController = StreamController.broadcast();

Stream get stream => _countController.stream;

Sink get sink => _countController.sink;

int get value => _count;

increment() {

sink.add(++_count);

}

dispose() {

_countController.close();

}

}

第二步:Scoped模式创建Bloc

创建bloc分三种:下面是Scoped方式

  • 全局单例创建
  • 局部创建
  • scoped

import 'package:flutter/material.dart';

import 'package:bloc_demo/scoped/blocs/count_bloc.dart';

class BlocProvider extends InheritedWidget {

CountBLoC bLoC = CountBLoC();

BlocProvider({Key key, Widget child}) : super(key: key, child: child);

@override

bool updateShouldNotify(_) => true;

//这里真正项目中可以使用范性创建对象

static CountBLoC *of*(BuildContext context) =>

(context.inheritFromWidgetOfExactType(BlocProvider) as BlocProvider).bLoC;

}

第三步:页面中使用方式

import 'package:flutter/material.dart';

import 'blocs/bloc_provider.dart';

class UnderPage extends StatelessWidget {

@override

Widget build(BuildContext context) {

final bloc = BlocProvider.*of*(context);//创建被观察者对象

print('build');

return Scaffold(

appBar: AppBar(

title: Text('Under Page'),

),

body: Center(

child: StreamBuilder(

stream: bloc.stream, //赋值观察者

initialData: bloc.value,

builder: (context, snapshot) => Text(

"You hit me: ${snapshot.data} times",

style: Theme.*of*(context).textTheme.display1,

)),

),

floatingActionButton: FloatingActionButton(

onPressed: () => bloc.increment(),//触发调用逻辑,这里的触发会调用bloc中的sink

child: Icon(Icons.*add*),

),

);

}

}

StreamBuilder中stream参数代表了这个stream builder监听的流,我们这里监听的是countBloc的value(它是一个stream)。

initData代表初始的值,因为当这个控件首次渲染的时候,还未与用户产生交互,也就不会有事件从流中流出。所以需要给首次渲染一个初始值。

builder函数接收一个位置参数BuildContext 以及一个snapshot。snapshot就是这个流输出的数据的一个快照。我们可以通过snapshot.data访问快照中的数据。也可以通过snapshot.hasError判断是否有异常,并通过snapshot.error获取这个异常。

StreamBuilder中的builder是一个AsyncWidgetBuilder,它能够异步构建widget,当检测到有数据从流中流出时,将会重新构建。

总结:

1.页面触发事件,触发bloc中方法发起业务逻辑,并获取相关数据,

2.再由bloc中的sink进行数据返回,数据将发送到具体页面(page)下的stream的监听下

3.由AsyncSnapshot对象将数据状态下发到具体的控件,并触发UI的重绘

框架四:Mobx

第一步:创建可观察对象

import 'package:mobx/mobx.dart';

part 'counter.g.dart';

class Counter = CounterBase with _$Counter;

final Counter counter = Counter();

abstract class CounterBase implements Store {

@observable

int value = 0;

@action

void increment() {

value++;

}

@action

void decrement() {

value--;

}

@action

void set(int value) {

this.value = value;

}

}

mobx会根据

part 'counter.g.dart';

class Counter = CounterBase with _$Counter;

生成对应的.g.dart文件

第二步:页面使用:

import 'package:flutter/material.dart';

import 'package:flutter_mobx/flutter_mobx.dart';

import 'package:flutter_mobx_project/mobx/counter.dart';

class SecondPage extends StatefulWidget {

@override

_SecondPageState createState() => _SecondPageState();

}

class _SecondPageState extends State {

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text('second page'),

),

body: Center(

child: Observer(

builder: (_) => Text(

'count is ${counter.value}',

style: TextStyle(fontSize: 30),

),

),

),

floatingActionButton: FloatingActionButton(

child: Icon(Icons.*add*),

onPressed: counter.increment,

),

);

}

}

框架五:fish_redux(https://pub.dev/packages/fish_redux/install)(https://github.com/alibaba/fish-redux

理解fish redux的组成

无法复制加载中的内容

|

image

|

image

|

image

  1. 用户点击勾选框,GestureDetector的onTap会被回调
  2. 通过buildView传入的dispatch函数对doneAction进行分发,发现todo_component的effect中无法处理此doneAction,所以将其交给pageStore的dispatch继续进行分发
  3. pageStore的dispatch会将action交给reducer进行处理,故doneAction对应的_markDone会被执行,对state进行clone,并修改clone后的state的状态,然后将这个全新的state返回
  4. 然后pageStore的dispatch会通知所有的listeners,其中负责界面重绘的_viewUpdater发现state发生变化,通知界面进行重绘更新
image

https://zhuanlan.zhihu.com/p/62588540

4.我们应该使用什么框架比较好?

之前没有接触过flutter可以先使用bloc,熟悉了flutter的一套语法及开发速度可以切换到fish-redux中

你可能感兴趣的:(Flutter 框架调研报告)