Skip to content

jacksonon/Dart

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

F计划

状态管理框架fish-redux

简析两个框架 两个框架的作用是不一样的。

flutter_boost是用来做混合项目栈管理的,由于官方推荐的混合开发多引擎模式会因为创建更多Engine而带来内存激增的问题,所以才有了复用机制的flutter_boost。

fish-redux是用来分治的,旨在将页面模块化,使界面或者条例更加清晰,有一种MVVM那种感觉;

想了解flutter_boost的话,首先要了解一下flutter官方默认的混合方案

flutter官方默认的混合方案是:多引擎模式,对于连续的Flutter页面(Widget)只需要在当前FlutterActivity打开即可,对于间隔的Flutter页面初始化新的引擎。

字面意思很好理解,如果flutter操作了一系列界面没有涉及到原生和flutter之间的切换,推荐你使用一个渲染引擎即可。如果涉及多层嵌套,推荐你每一个切换点都创建一个flutter engine用来做渲染;

这就会导致如果频繁切换会造成不必要的开销,所以比较考量软件结构涉及与页面路径层级涉及,具有了比较大的限制。

多引擎模式会造成以下几个问题:

  1. 内存问题。多引擎下每个引擎之间的isolate是相互独立的。所以没一个引擎底层都维护了图片缓存等比较消耗内存的对象,造成不必要的内存消耗。
  2. 资源冗余。每个Flutter实例在基础的platform task runner线程外,都会持有UI / GPU / IO这三个task runner 。多余的flutter实例会导致线程开销变得庞大。
  3. 通讯复杂。flutter页面彼此间隔离在自己的isolate中,页面通讯复杂、
  4. 插件注册问题。插件依赖Messager传递信息,而messager由flutterNativeView实现。多引擎会导致插件的注册和通信变得混乱且难以维护。

flutter_boost提供的方案:

所有的Flutter页面共享一个Flutter实例(FlutterView),这种方式能够有效避免多引擎方式带来的各种问题,但是单例的实现也使页面的管理变得更加复杂。 关于flutter_boost的实现大概分为2部分:

  1. Native部分 1.1 Container:native容器,iOS是ViewController,Android是Fragment 1.2 Container Manager:Native容器管理器 1.3 Messaging:基于Message Channel的消息通道,负责通信功能
  2. Dart部分 2.1 Container:Flutter widget容器,Flutter navigator路由器 2.2 Container Manager:Flutter 容器管理器 2.3 Coordinator:协调器,接收Native Messaging消息,负责调用Container Manager的状态管理

fish-redux的理解首先要理解redux的概念,其实redux的概念并不是新兴的。

Redux最主要是用作应用状态的管理。简言之,Redux用一个单独的常量状态树(对象)保存这一整个应用的状态,这个对象不

能直接被改变。当一些数据变化了,一个新的对象就会被创建(使用actions和reducers)

Redux的核心概念有3个:action reducer store

  1. action:用来传递操作state的信息到store,是store的唯一来源,以对象的形式存在。
  2. reducer:用来处理action,通过传入旧的state和action来指明如何更新state。
  3. store:store是将该类对应的操作聚合;维持应用的State,提供dispatch()更新、getState()获取方法,注册注销监听器等;Redux应用只有一个单一的store

介绍完了Redux,我们来了解一下flutter中fish-redux的一些基本概念。

Fish Redux 是闲鱼团队基于 Redux 做的一次量身改良,通过 Redux 做集中化的可观察的数据管理。

FR 是一个基于 Redux 数据管理的组装式 flutter 应用框架, 特别适用于构建中大型的复杂应用,对于传统 Redux 在使用层面上的两大缺点做了重大改良,

具体做法是:首先规定一个组件需要定义一个数据(Struct)和一个 Reducer,同时组件之间存在着父依赖子的关系。 通过这层依赖关系去解决了 集中 和 分治 之间的矛盾,而对 Reducer 的手动层层 Combine 变成由框架自动完成,使之简化了使用 Redux 的困难,同时也得到了理想的集中的效果和分治的代码。

即一个Page由几部分组成:State Action Reducer Store Middleware,分别做一下简单的介绍:

  1. page代表一个页面,继承自 component。它由view(即展示ui的Widget)、state、reducer、effect等组成
  2. state用来保存 page/component(页面/组件)的状态,即存放数据。
  3. action是我们定义的意图。我们需要处理某些操作或事件时,通过发送(dispatch)特定的 action,让对应action的接收者进行处理。
  4. reducer的作用是接收某个意图(action),然后对数据做出修改,即更新状态(state)。Reducer 接受处理的 Action,以 { verb } 命名
  5. effect的用法跟 reducer 类似,但是责任不同。他负责处理“副作用”,这是函数式编程的概念。在这里简单地理解为,reducer是负责(state)的更新,effect 负责 state 更新之外的事情。Effect 接受处理的 Action,以 on{ Verb } 命名
  6. store维持全局的状态(state),应用只有一个单一的 store 。

使用flutter_boost(iOS)

  • 在Dart工程,即Flutter项目中,编辑pubspec.yml。增加flutter_boost的使用,具体install方式,可以去pub.dev的Install拷贝。然后点击pub-get,即可完成插件的下载。
flutter_boost: git: url: 'https://github.com/alibaba/flutter_boost.git' ref: 'task/task_v1.12.13_support_hotfixes' 
  • 在创建的有状态的State的class中,重写initState()方法。并在里面注册你的flutter_boost路由,并实现路由跳转方法等。
class _MyAppState extends State<MyApp> { @override void initState() { super.initState(); // 注册页面,每个页面的名称在native端和flutter端需要一致 FlutterBoost.singleton.registerPageBuilders({ 'embeded': (pageName, params, _)=>EmbededFirstRouteWidget(), 'first': (pageName, params, _) => FirstRouteWidget(), 'firstFirst': (pageName, params, _) => FirstFirstRouteWidget(), 'second': (pageName, params, _) => SecondRouteWidget(), 'secondStateful': (pageName, params, _) => SecondStatefulRouteWidget(), 'tab': (pageName, params, _) => TabRouteWidget(), 'platformView': (pageName, params, _) => PlatformRouteWidget(), 'flutterFragment': (pageName, params, _) => FragmentRouteWidget(params), ///可以在native层通过 getContainerParams 来传递参数 'flutterPage': (pageName, params, _) { print("flutterPage params:$params"); return FlutterRouteWidget(params:params); }, }); FlutterBoost.singleton.addBoostNavigatorObserver(TestBoostNavigatorObserver()); } @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Boost example', builder: FlutterBoost.init(postPush: _onRoutePushed), home: Container( color:Colors.white )); } void _onRoutePushed( String pageName, String uniqueId, Map params, Route route, Future _) { } } 
  • 使用原生项目混合flutter的官方的混合方式即可,使用源码混合方式,修改podfile如下:可以很轻松的引入Flutter相应的framework
# Uncomment the next line to define a global platform for your project # platform :ios, '9.0' # 引入flutter链接 flutter_application_path = '../my_flutter' load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') target 'iosflutter' do # Comment the next line if you don't want to use dynamic frameworks use_frameworks! # Pods for iosflutter 将flutter工程产物导入该位置;这种方式就需要在本地有flutter那个项目,每次运行都需要git pull && pod install保证最新 install_all_flutter_pods(flutter_application_path) # Basic pods end 
  • 新建一个类,实现flutter_boost的协议,提供一些原生页面与native界面的push、pop和present、dismiss操作;这个类我们可以在flutter_boost的example中看见并根据项目需求加以修改即可。使用原生的push或present进行界面间跳转操作,如:
[self.navigationController presentViewController:vc animated:animated completion:^{ if(completion) completion(YES); }]; 

使用如下方式获取flutter渲染的界面:

FLBFlutterViewContainer *vc = FLBFlutterViewContainer.new; [vc setName:name params:params]; 
  • 在AppDelegate中为flutter_boost提供一个跳转路由。其它如原生处理即可。
PlatformRouterImp *router = [PlatformRouterImp new]; [FlutterBoostPlugin.sharedInstance startFlutterWithPlatform:router onStart:^(FlutterEngine *engine) { }]; 
  • 可以愉快的编写dart代码了。并且可以再原生种进行测试:比如我想进行页面的跳转。就是这么简单。
[FlutterBoostPlugin open:@"second" urlParams:@{@"present":@(YES),kPageCallBackId:@"MycallbackId#2"} exts:@{@"animated":@(YES)} onPageFinished:^(NSDictionary *result) { NSLog(@"call me when page finished, and your result is:%@", result); } completion:^(BOOL f) { NSLog(@"page is presented"); }]; 

使用fish-redux

使用Android Studio可以再plugin下载一个fish-redux插件,可以快速创建dart-redux模板,我们只需要按照需求编辑模板即可。创建模板的方式简单快捷。只需要输入一个Module Name即可。

模板创建出来最简单的模块如下: action.dart effect.dart page.dart reducer.dart view.dart

  • 通常我们创建一个模板,第一步是实现它的UI,我们在上面介绍过,UI对应的事view.dart
import 'package:fish_redux/fish_redux.dart'; import 'package:flutter/material.dart'; import 'action.dart'; import 'state.dart'; Widget buildView(EntranceState state, Dispatch dispatch, ViewService viewService) { // return Container(); return Scaffold( appBar: AppBar( title: Text('Fish redux'), backgroundColor: state.themeColor, ), body: Container( child: Center( child: RaisedButton( padding: EdgeInsets.fromLTRB(40, 0, 40, 0), color: Colors.green, child: Text( state.showLabel, style: TextStyle(color: Colors.orange), ), onPressed: () { // todo 点击事件 // dispatch(EntranceActionCreator.onChangeShowLabel()); dispatch(EntranceActionCreator.onOpenGrid()); }, ), ), ), ); } 
  • 在state中添加你自己需要的属性及是否继承全局属性等。
import 'dart:ui'; import 'package:fish_redux/fish_redux.dart'; import 'package:flutterappfishredux/store/state.dart'; // clone方法,用来获取state,在reducer用会用到来merge state合并状态 class EntranceState implements Cloneable<EntranceState>, GlobalBaseState { // 定义一些用到的数据 String showLabel = '跳转'; int counter = 10; @override Color themeColor; @override EntranceState clone() { return EntranceState() ..showLabel = showLabel ..counter = counter; } } EntranceState initState(Map<String, dynamic> args) { final EntranceState state = EntranceState(); return state; } 
  • 在page中做状态、视图、事件、list驱动器的初始化和绑定操作
import 'package:fish_redux/fish_redux.dart'; // 代表一个界面 // 继承自component // 使用FlutterRedexPlugin可以快速常见redux开发模板 import 'effect.dart'; // 处理副作用,负责state更新之外的事情 import 'reducer.dart'; // 接收action, 然后对数据做出修改,即更新状态(state) import 'state.dart'; // 保存页面的状态,即存放数据; import 'view.dart'; // 绘制的基本组件 // class EntrancePage extends Page<EntranceState, Map<String, dynamic>> { EntrancePage() : super( // 这是三要素 initState: initState, // 初始化数据存储位置 effect: buildEffect(), // 初始化除state更新之外的其它事情 view: buildView, // 基础页面 // reducer: buildReducer(), // 更新state // dependencies: Dependencies<EntranceState>( // 未知 // adapter: null, // slots: <String, Dependent<EntranceState>>{ // }), // middleware: <Middleware<EntranceState>>[ // 页面私有AOP。如果需要 // ], ); } 
  • 在action中使用enum定义时间,并且在ActionCreator中创建对应的action映射方法
import 'package:fish_redux/fish_redux.dart'; //TODO replace with your own action enum EntranceAction { changeShowLabel, openGrid} class EntranceActionCreator { // 改变showLabel文案的方法,根据我的理解会映射到effect中 static Action onChangeShowLabel() { print('调用修改文本方法onChangeShowLabel'); return const Action(EntranceAction.changeShowLabel); } static Action onOpenGrid() { return const Action(EntranceAction.openGrid); } } 
  • 在effect和reducer中对功能进行实现
import 'package:fish_redux/fish_redux.dart'; import 'package:flutter/material.dart' hide Action; import 'action.dart'; import 'state.dart'; // 页面初始化或异步请求这样的事件 // 接收并处理事件 Effect<EntranceState> buildEffect() { return combineEffects(<Object, Effect<EntranceState>>{ EntranceAction.changeShowLabel: _onChangeShowLabel, EntranceAction.openGrid: _onOpenGrid, }); } // 接收事件 void _onOpenGrid(Action action, Context<EntranceState> ctx) { Navigator.of(ctx.context).pushNamed('grid_page', arguments: null); } // 修改方法 void _onChangeShowLabel(Action action, Context<EntranceState> ctx) { ctx.state.showLabel = '你好'; } ====== reducer ====== import 'package:fish_redux/fish_redux.dart'; import 'action.dart'; import 'state.dart'; // 页面点击修改主题等 Reducer<EntranceState> buildReducer() { return asReducer( <Object, Reducer<EntranceState>>{ // EntranceAction.changeShowLabel: _onChangeShowLabel }, ); } 

在flutter_boost中使用fish-redux

集成方式非常简单,将flutter_boost对应的页面使用page提供的buildPage()方法,并传入params即可。

FlutterBoost.singleton.registerPageBuilders({ // 在flutter_boost的注册中,将实例方法改为由fish-redux创建的page的buildPage(params)方法。将数据传进去即可在原生中继续使用这种路由映射。   'HomePage': (name, params, _) => HomePage().buildPage(params) }) 

About

Flutter And Native Mix And Dart Knowledge

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published