前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >「 Flutter 项目实战 」设计企业级项目入口 main.dart 设计与实现 ( GSYGithubApp 源码解读·二 )

「 Flutter 项目实战 」设计企业级项目入口 main.dart 设计与实现 ( GSYGithubApp 源码解读·二 )

作者头像
圆号本昊
发布于 2021-12-30 08:33:35
发布于 2021-12-30 08:33:35
1.2K00
代码可运行
举报
文章被收录于专栏:github@hornhuanggithub@hornhuang
运行总次数:0
代码可运行

提示:温馨提示一下哈,这篇文章主要是针对 GitHub 上 12+k 顶级项目「 CarGuo/gsy_github_app_flutter 」 的源码解读,因为这是我目前见过最棒、最具有企业级水平的 Flutter 开源项目,整个项目的设计令我倾佩,所以我希望与大家一起分享它 注意:我并非什么大神,只是一个热爱分享,并希望带大家一起进步的码者,所以我也无法保证本文的方案就一定是最好的,如果有更好的方案,也希望大家在评论区分享。那么与君共勉,我们开始吧 ~

一、前言

  • 初始化 Flutter project 时,系统会给我们一个默认的 main.dart 文件,但在世纪开发中我不建议直接使用,因为它的功能过于简单(只是加载了界面),并不能满足实际复杂的开发需求
  • 我将给大家呈现的 main.dart 设计方案讲具有:失败页、错误日志获取、数据共享和网络监听等功能,下面我们正式进入

二、main.dart

  • 由于相比默认 main.dart 文件,新方案功能要多很多,所以我们需要拆分为:main.dart 和 app.dart 两个文件来实现
  • 在 main.dart 中需要实现三个功能:异常捕获、错误页展示、主页面加载

2.1 异常捕获 - runZoned

  • 在 Flutter 中,还无法捕获的异常,如调用空对象方法异常、Futurer 中的异常等
  • 同样,对于在 Dart 中的同步异常和异步异常,同步异常可以通过 try/catch 捕获,但异步异常则比较麻烦
  • 举个异步异常的栗子:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
try{
    Future.delayed(Duration(seconds: 1)).then((e) => Future.error("asynchronous error"));
}catch (e){
    // TODO Report
}
  • Dart 中有一个 runZoned(…) 方法( Zone 表示一个代码执行的环境范围)
  • 在 Zone 中可以捕获日志输出、Timer 创建、微任务调度的行为,同时 Zone 也可以捕获所有未处理的异常
  • 将上面代码结合 runZoned 实现就是:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  runZoned(() {
    Future.delayed(Duration(seconds: 1)).then((e) => Future.error("asynchronous error"));
  }, onError: (Object obj, StackTrace stack) {
    // crash 日志打印与上报
  })
  • 所以 main() 方法就可以相应的写作:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void main() {
  runZoned(() {
  	// TODO some init
    runApp(FlutterReduxApp());
  }, onError: (Object obj, StackTrace stack) {
    // crash 日志打印与上报
    print(obj);
    print(stack);
  });
}

2.2 错误页展示 - ErrorWidget

  • Flutter 在很多关键的方法进行了异常捕获
  • 举个例子,当布局发生越界或不和规范时,会自动弹出一个错误界面:
  • 现网环境中,我们不能直接给用户展示这个页面,这时就需要 ErrorWidget。让它处于最底层来覆盖这个这样的页面
  • 添加上 ErrorWidget 后如下所示:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void main() {
  runZoned(() {
    ErrorWidget.builder = (FlutterErrorDetails details) {
      Zone.current.handleUncaughtError(details.exception, details.stack);
      return ErrorPage(
          details.exception.toString() + "\n " + details.stack.toString(), details);
    };
    runApp(FlutterReduxApp());
  }, onError: (Object obj, StackTrace stack) {
  	// crash 日志打印与上报
    print(obj);
    print(stack);
  });
}
  • 其中 ErrorWidget 所创建的错误页:ErrorPage 是我们自定义的
  • 其主要功能应包括:错误日志上传、返回上一界面
  • 具体逻辑需根据实际环境设计,由于异常上报跟本文主题关系无关,大家可以参照 error_page 源码 进行设计

2.3 数据共享 - InheritedWidget

  • 由于Flutter采用节点树的方式组织页面,以致于一个普通页面的节点层级会很深。
  • 此时,我们如果还是一层层传递数据,当需要修改数据时,就会比较麻烦。
  • 《Flutter 实战》中讲到:InheritedWidget 是 Flutter 中非常重要的一个功能型组件,它提供了一种数据在 widget 树中从上到下传递、共享的方式
  • 比如我们在应用的根 widget 中通过 InheritedWidget共享了一个数据,那么我们便可以在任意子 widget 中来获取该共享的数据!
  • 这个特性在一些需要在 widget 树中共享数据的场景中非常方便!如Flutter SDK 中正是通过 InheritedWidget 来共享应用主题(Theme)和 Locale (当前语言环境)信息的。

InheritedWidget 基本使用: 还没有学会 使用的同学可以先查看这篇文章进行学习 「flutter 必知必会」详细解析数据共享 InheritedWidget 完整使用

2.3.1 共享的数据
  • 根据 OOP 原则,我们将需共享的数据独立出一个类 EnvConfig
  • 新建 env_config.dart 文件内容如下
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
///环境配置
@JsonSerializable(createToJson: false)
class EnvConfig {
  final String env;
  final bool debug;

  EnvConfig({
    this.env,
    this.debug,
  });

  factory EnvConfig.fromJson(Map<String, dynamic> json) => _$EnvConfigFromJson(json);
}
  • 由于这些配置一般是通过本地存储,或者联网时拉取
  • 所以其实例化采用 fromJson 方法,同时用户更新后也可以在转为 json 串存储到本地进行覆盖
2.3.2 封装与管理 ConfigWrapper

数据绑定的作用分两种:跟 UI 结合的内容刷新(如页面文字内容),全局共享的配置数据(如用户登录状态,系统颜色等) 由于本文是对 main.dart 的解析,所以我们针对第二种情况进行分析即可 对第一种情况感兴趣的同学可以点击上面链接查看

  • 我们知道 runApp 的参数是 WIdget 类型,同时我们需要将界面 MaterialApp 和数据进行绑定
  • 所以为了方便管理,我们新建一个 config_wrapper 文件,同时在这个文件里实现类 ConfigWrapper
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
///往下共享环境配置
class ConfigWrapper extends StatelessWidget {
  ConfigWrapper({Key key, this.config, this.child});

  @override
  Widget build(BuildContext context) {
    ///设置 Config.DEBUG 的静态变量
    Config.DEBUG = this.config.debug;
    print("ConfigWrapper build ${Config.DEBUG}");
    return new _InheritedConfig(config: this.config, child: this.child);
  }

  static EnvConfig of(BuildContext context) {
    final _InheritedConfig inheritedConfig =
    context.dependOnInheritedWidgetOfExactType<_InheritedConfig>();
    return inheritedConfig.config;
  }

  final EnvConfig config;

  final Widget child;
}
  • 这个类的作用主要是对功能的封住,比如获取/更新数据,就可以通过 ConfigWrapper.of(…).methed(),来进行操作
2.3.3 绑定数据与视图 _InheritedConfig
  • 其中,将数据与视图(MaterialApp)绑定需要使用到 InheritedWidget
  • 同样在 config_wrapper.dart 文件中,我们新建一个类 _InheritedConfig
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class _InheritedConfig extends InheritedWidget {
  const _InheritedConfig(
      {Key key, @required this.config, @required Widget child})
      : assert(child != null),
        super(key: key, child: child);

  final EnvConfig config;

  @override
  bool updateShouldNotify(_InheritedConfig oldWidget) =>
      config != oldWidget.config;
}
  • 每一次调用/修改绑定的数据,都会调用 updateShouldNotify 这个方法
  • 这方法是用来判断是否需要通知视图,可更具具体场景进行设定
  • 比如数字数据变化时修改,或者数据变不变都修改

updateShouldNotify : Whether the framework should notify widgets that inherit from this widget.

2.3.4 获取数据与更新
  • 就如前面的流程图所示,我们通过 ConfigWrapper.of(…) 方法就能获得配置的数据对象
  • 之后其中数据,进行对应的修改、赋值操作即可,修改后会调用到 updateShouldNotify 来确认是否通知 UI 更新

2.4 页面编写 MaterialApp

  • 页面的编写主要注意两个
  • 一方面是页面的更新(flutter_redux / InheritedWidget)
  • 另一方面是诸如网络异常、登录成功之类,各种提示的显示(eventBus)
2.4.1 页面独立
  • 首先根据 oop 六大原则,我们需要将 app 的页面独立出一个类
  • 这里建议将其命名为 app.dart 更为合理,因为有入口的意思
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class FlutterReduxApp extends StatefulWidget {
  @override
  _FlutterReduxAppState createState() => _FlutterReduxAppState();
}

class _FlutterReduxAppState extends State<FlutterReduxApp> {
  // ...
}

2.5 页面更新 flutter_redux

  • 关于数据与页面的绑定/更新,前面已经介绍了 InheritedWidget
  • flutter_redux 是在 InheritedWidget 的基础上封装的,对于 UI 上数据的更新与管理更加方便高效,但是如果数据很简单,或者不涉及 UI 那么使用 InheritedWidget 更简单一些也就比较适合

这里如果是还不会使用 flutter_redux 的同学可以先看这篇文章 「 flutter 必知必会 」最强数据管理方案 flutter_redux 使用解析

  • OK,那么一个企业级项目的 main.dart 木块中该如何使用 flutter_redux 呢?
  • 下面我们就以 GSYGitHubApp 为例,看看优秀的 app 是怎么实现的
2.4.1 创建 store
  • 要使用 flutter_redux 来对页面进行管理,就系要实例化 store
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  /// 创建Store,引用 GSYState 中的 appReducer 实现 Reducer 方法
  /// initialState 初始化 State
  final store = new Store<GSYState>(
    appReducer,

    ///拦截器
    middleware: middleware,

    ///初始化数据
    initialState: new GSYState(
        userInfo: User.empty(),
        login: false,
        themeData: CommonUtils.getThemeData(GSYColors.primarySwatch),
        locale: Locale('zh', 'CH')),
  );
  • 但是使用 store 需要准备 appReducer、middleware、GSYState 四个模块,下面我们逐个来看看
2.4.2 创建 Reducer
  • 源码中 Reducer 是一个方法 typedef State Reducer(State state, dynamic action);
  • 我们自定义了 appReducer 用于创建 store
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
GSYState appReducer(GSYState state, action) {
  return GSYState(
    ///通过 UserReducer 将 GSYState 内的 userInfo 和 action 关联在一起
    userInfo: UserReducer(state.userInfo, action),

    ///通过 ThemeDataReducer 将 GSYState 内的 themeData 和 action 关联在一起
    themeData: ThemeDataReducer(state.themeData, action),

    ///通过 LocaleReducer 将 GSYState 内的 locale 和 action 关联在一起
    locale: LocaleReducer(state.locale, action),
    login: LoginReducer(state.login, action),
  );
}
  • 那么 GSYState 需要如何设计呢?
2.4.3 创建 State
  • 全局Redux store 的对象,保存State数据
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class GSYState {
  ///用户信息
  User userInfo;

  ///主题数据
  ThemeData themeData;

  ///语言
  Locale locale;

  ///当前手机平台默认语言
  Locale platformLocale;

  ///是否登录
  bool login;

  ///构造方法
  GSYState({this.userInfo, this.themeData, this.locale, this.login});
}
2.4.4 拦截器 middleware
  • 拦截器顾名思义就是拦截消息是否再往下传递
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
final List<Middleware<GSYState>> middleware = [
  EpicMiddleware<GSYState>(loginEpic),
  EpicMiddleware<GSYState>(userInfoEpic),
  EpicMiddleware<GSYState>(oauthEpic),
  UserInfoMiddleware(),
  LoginMiddleware(),
];
  • 可以看到 GSYGitHubApp 中设置了 5 个拦截器, 如果均满足其中的筛选条件,就可以进行后续的 UI 刷新操作
  • 就比如第一个‘登录’,如果用户没登录,自然不用再往后了,按照 app 设计的逻辑,这时需要先跳转登录才行
2.4.5 全局注册
  • 在 _HomePageState 的 build 方法中, 配置 store 方便后续使用
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  @override
  Widget build(BuildContext context) {
    return StoreBuilder<GSYState>(
      builder: (context, store) {
        double size = 200;
        return Material(
          ...
        );
      },
    );
  }
2.4.6 注册更新监听
  • 在需要 Store 中数据的地方/页面,通过 StoreConnector 进行注册
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class DemoUseStorePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    ///通过 StoreConnector 关联 GSYState 中的 User
    return new StoreConnector<GSYState, User>(
      ///通过 converter 将 GSYState 中的 userInfo返回
      converter: (store) => store.state.userInfo,
      ///在 userInfo 中返回实际渲染的控件
      builder: (context, userInfo) {
        return new Text(
          userInfo.name,
          style: Theme.of(context).textTheme.headline4,
        );
      },
    );
  }
}
2.4.7 触发
  • 通过 store.dispatch(…) 可以调用到 appReducer ,并对 store 中的数据进行刷新
  • 同时可以通知到注册了这些数据的地方,让他们自动取刷新对应的 ui
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  ///初始化用户信息
  static initUserInfo(Store store) async {
    var token = await LocalStorage.get(Config.TOKEN_KEY);
    var res = await getUserInfoLocal();
    if (res != null && res.result && token != null) {
      store.dispatch(UpdateUserAction(res.data));
    }

    ///读取主题
    String themeIndex = await LocalStorage.get(Config.THEME_COLOR);
    if (themeIndex != null && themeIndex.length != 0) {
      CommonUtils.pushTheme(store, int.parse(themeIndex));
    }

    ///切换语言
    String localeIndex = await LocalStorage.get(Config.LOCALE);
    if (localeIndex != null && localeIndex.length != 0) {
      CommonUtils.changeLocale(store, int.parse(localeIndex));
    } else {
      CommonUtils.curLocale = store.state.platformLocale;
      store.dispatch(RefreshLocaleAction(store.state.platformLocale));
    }

    return new DataResult(res.data, (res.result && (token != null)));
  }

2.5 引入 event_bus

  • 由于 HomePage 是最原始/基础的 page ,所以我们可以吧网络请求的 Toast 显示在这个页面上来
  • 这样无论是哪个模块发生问题,HomePage 监听到后都能统一的显示 Toast
  • 很明显这是一个多对一的情形(多个发送方对一个接收方 HomePage),而且发送事件的逻辑是分散在不同功能模块中的,所以我们不要采用 event_bus(事件总线来实现)

如果还不熟悉 event_bus 的同学,可以先看这篇博客 https://blog.csdn.net/qq_43377749/article/details/115050851?spm=1001.2014.3001.5501

2.5.1 实例化 eventbus
  • 使用 event_bus 进行事件的发送和接收都是通过eventBus 对象进行的
  • 所以我们需要先实例化一个 eventBus 对象
  • 为了方便管理,我们先新建一个文件 index.dart 来用于管理项目中的 eventBus 对象
  • 具体实例化过程如下
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import 'package:event_bus/event_bus.dart';

EventBus eventBus = new EventBus();
2.5.2 定义消息 event 对象
  • 在传递网络请求结果的事件时,我们将其内容封装在一个对象中传递
  • 通常情况下我们只需要在请求错误时,向用户反馈结果
  • 所以这里我们只需封装一个 HttpErrorEvent 对象(当然如果需要,我们也可以添加更多的类型对象)
  • 这里我们新建一个类:http_error_event.dart 来专门管理相关对象
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class HttpErrorEvent {
  final int code;

  final String message;

  HttpErrorEvent(this.code, this.message);
}
2.5.3 创建监听器
  • 我们需要为 HomePage 建立一个监听器,来监听传来的各种事件
  • 这里一般采用混合注入的方式
  • 首先我们采用 mixin 方式建立,同时让他 on State
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mixin HttpErrorListener on State<FlutterReduxApp> {
  StreamSubscription stream;

  ///这里为什么用 _context 你理解吗?
  ///因为此时 State 的 context 是 FlutterReduxApp 而不是 MaterialApp
  ///所以如果直接用 context 是会获取不到 MaterialApp 的 Localizations 哦。
  BuildContext _context;

  @override
  void initState() {
    super.initState();

    ///Stream演示event bus
    stream = eventBus.on<HttpErrorEvent>().listen((event) {
      errorHandleFunction(event.code, event.message);
    });
  }

  @override
  void dispose() {
    super.dispose();
    if (stream != null) {
      stream.cancel();
      stream = null;
    }
  }

  ///网络错误提醒
  errorHandleFunction(int code, message) {
    switch (code) {
      case Code.NETWORK_ERROR:
        showToast(GSYLocalizations.i18n(_context).network_error);
        break;
      case 401:
        showToast(GSYLocalizations.i18n(_context).network_error_401);
        break;
      case 403:
        showToast(GSYLocalizations.i18n(_context).network_error_403);
        break;
      case 404:
        showToast(GSYLocalizations.i18n(_context).network_error_404);
        break;
      case 422:
        showToast(GSYLocalizations.i18n(_context).network_error_422);
        break;
      case Code.NETWORK_TIMEOUT:
        //超时
        showToast(GSYLocalizations.i18n(_context).network_error_timeout);
        break;
      case Code.GITHUB_API_REFUSED:
        //Github API 异常
        showToast(GSYLocalizations.i18n(_context).github_refused);
        break;
      default:
        showToast(GSYLocalizations.i18n(_context).network_error_unknown +
            " " +
            message);
        break;
    }
  }

  showToast(String message) {
    Fluttertoast.showToast(
        msg: message,
        gravity: ToastGravity.CENTER,
        toastLength: Toast.LENGTH_LONG);
  }
}
2.5.4 发送事件
  • 发送消息时只要调用 eventBus.fire(…) 即可
  • 参数是需要传递的消息对象,这里也就是 HttpErrorEvent
  • 带这个项目中,使用的部分诸如
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  static errorHandleFunction(code, message, noTip) {
    if (noTip) {
      return message;
    }
    if(message != null && message is String && (message.contains("Connection refused") || message.contains("Connection reset"))) {
      code = GITHUB_API_REFUSED;
    }
    eventBus.fire(new HttpErrorEvent(code, message));
    return message;
  }
2.5.5 接受事件
  • 消息发送后,经过过滤器等步骤的传递
  • 最后会传递到上面‘监听器’的 listen 方法下
  • 再由 listen 的回调进行后续操作(比如这个项目中,监听器是捆绑在 _HomePage 上的,因此可以在页面上显示 Toast 等等)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  @override
  void initState() {
    super.initState();

    ///Stream演示event bus
    stream = eventBus.on<HttpErrorEvent>().listen((event) {
      errorHandleFunction(event.code, event.message);
    });
  }

  ///网络错误提醒
  errorHandleFunction(int code, message) {
    switch (code) {
      case Code.NETWORK_ERROR:
        showToast(GSYLocalizations.i18n(_context).network_error);
        break;
      case 401:
        showToast(GSYLocalizations.i18n(_context).network_error_401);
        break;
        // ...
      default:
        showToast(GSYLocalizations.i18n(_context).network_error_unknown +
            " " +
            message);
        break;
    }
  }

  showToast(String message) {
    Fluttertoast.showToast(
        msg: message,
        gravity: ToastGravity.CENTER,
        toastLength: Toast.LENGTH_LONG);
  }
2.5.6 完整代码

三、总结

  • 限于篇幅原因,这里就不展开讲了,后续会出一个相关的视频进行更详细的解析 bilibili@黎明韭菜
  • 设计一个完美的程序入口不是件容易的事情,也希望大家有更完美的方案能在评论区分享
  • 最后感谢大家的三连或者关注支持,我们下期博客再见
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/03/24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Flutter完整开发实战详解(四、 Redux、主题、国际化)
作为系列文章的第四篇,本篇主要介绍 Flutter 中 Redux 的使用,并结合Redux 完成实时的主题切换与多语言切换功能。
GSYTech
2018/08/19
1.3K0
Flutter完整开发实战详解(四、 Redux、主题、国际化)
Flutter完整开发实战详解(四、 Redux、主题、国际化)
作为系列文章的第四篇,本篇主要介绍 Flutter 中 Redux 的使用,并结合Redux 完成实时的主题切换与多语言切换功能。
GSYTech
2018/08/22
1.3K0
Flutter完整开发实战详解(四、 Redux、主题、国际化)
「 flutter 必知必会 」最强事件发布/订阅框架方案 event_bus 全局事件总线使用解析
一、前言 EventBus是全局事件总线,底层通过Stream来实现;它可以实现不同页面的跨层访问,通过Stream的机制来实现不同widget之间的状态共享. 二、作用 举个例子: 你有一个主界面,里面有一些信息可能会修改,但触发源不在该界面,是在其他的界面触发了一些事件后,首页的内容需要做修改。如果没有EventBus,也有很多的方式可以实现,譬如定义全局静态变量、或者定义个CallBack接口传出去等等。不管怎样,总是要把主页和触发源关联起来,这是相当难受的,这不但会导致代码量暴涨,同时还会导致耦合
圆号本昊
2021/09/24
1.2K0
[- Flutter 状态篇 -] 主题色切换+国际化 三连
很多Flutter状态管理文章都是改计数器,搞得总感觉用了反而麻烦。搞太复杂的例子,一篇文章又不现实。就拿主题色切换+国际化开刀吧。本文会说一下provoder、BLoC和redux的三种实现主题色切
张风捷特烈
2020/04/30
3.5K0
[- Flutter 状态篇 -] 主题色切换+国际化 三连
Flutter完整开发实战详解(十二、全面深入理解状态管理设计)
在所有 响应式编程 中,状态管理一直老生常谈的话题,而在 Flutter 中,目前主流的有 scope_model 、BloC 设计模式 、flutter_redux 、fish_redux 等四种设计,它们的 复杂度 和 上手难度 是逐步递增的,但同时 可拓展性 、解耦度 和 复用能力 也逐步提升。
GSYTech
2019/05/14
2.3K0
Flutter完整开发实战详解(二、 快速开发实战篇)
 作为系列文章的第二篇,继《Flutter完整开发实战详解(一、Dart语言和Flutter基础)》之后,本篇将为你着重展示:如何搭建一个通用的Flutter App 常用功能脚手架,快速开发一个完整的 Flutter 应用。
GSYTech
2018/08/11
5.1K0
Flutter完整开发实战详解(二、 快速开发实战篇)
【Flutter 专题】99 初识 EventBus
和尚在 Android 开发过程中经常会用到 EventBus 事件分发机制,EventBus 遵从 publish/subscribe 模式,即发布/订阅模式;简化了模块之间通信,对于项目的解耦很实用;而 Flutter 也提供了相应的 event_bus 插件,今天和尚学习尝试一下;
阿策小和尚
2020/09/01
1.1K0
【Flutter 专题】99 初识 EventBus
Flutter 面试知识点集锦
谷歌大会之后,有不少人咨询了我 Flutter 相关的问题,其中有不少是和面试相关的,如今一些招聘上也开始罗列 Flutter 相关要求,最后想了想还是写一期总结吧,也算是 Flutter 的阶段复习。
GSYTech
2019/05/17
5.3K0
Flutter 面试知识点集锦
Flutter异常监测与上报
众所周知,软件项目的交付是一个复杂的过程,任何原因都有可能导致交付的失败。很多时候经常遇到的一个现象是,应用在开发测试时没有任何异常,但一旦上线就问题频出。出现这些异常,可能是因为不充分的机型适配或者用户糟糕的网络状况造成的,也可能是Flutter框架自身缺陷造成的,甚至是操作系统底层的问题。
xiangzhihong
2020/04/06
3.1K0
flutter全局数据共享通知方案
让我们先抛开Flutter这个平台说话,如果让你实现数据共享,你能想到的基础方案有哪些。
老码小张
2018/09/13
6.1K2
Flutter 如何跨组件传递数据
InheritedWidget 是 Flutter 中非常重要的一个功能型 Widget,它可以高效的将数据在Widget 树中向下传递、共享,这在一些需要在 Widget 树中共享数据的场景中非常方便,如 Flutter 中,正是通过 InheritedWidget 来共享应用主题( Theme )和 Locale (当前语言环境)信息的。
网罗开发
2021/02/26
2.9K0
Flutter 如何跨组件传递数据
「 flutter 必知必会 」最强数据管理方案 flutter_redux 使用解析
一、前言 上篇文章我们讨论了 InheritedWidget 的使用,但是当 widget 数量很多时,使用起来会越来越麻烦,所以本文再给大家分享下,flutter_redux 的使用方法 flutter_redux是基于InheritedWidget封装的用于Widget树的数据传递与共享的的一套框架,它能高效的完成数据共享,进而达到ui及时更新等目的,使用起来略显复杂,一般不是很多的数据更新不建议使用,直接用InheritedWidget就能解决,当Widget绑定的很多的时候,使用起来就会很爽了。
圆号本昊
2021/09/24
8030
「 flutter 必知必会 」最强数据管理方案 flutter_redux 使用解析
Flutter主题切换 flutter redux
创建一个State对象AppState,用于储存需要共享的主题数据,并且完成AppState初始化工作,如下面代码所示
易寒
2022/01/20
8880
使用Flutter_Redux实现主题切换
1. 添加依赖 dependencies: flutter_redux: ^0.6.0 2. 定义State /// 1.定义状态 class AppStates { ThemeData themeData; AppStates({this.themeData}); } /// 2.提供appReducer方法 AppStates appReducer(AppStates states, dynamic action) { return AppStates( /// 使用对应的
前端小鑫同学
2022/12/24
6590
Flutter技术与实战(4)
* 以 Text 的部分源码为例,说明 StatelessWidget 的构建过程。
八归少年
2022/06/29
11.1K0
Flutter技术与实战(4)
「 flutter 必知必会 」详细解析数据共享 InheritedWidget 完整使用
「 flutter 必知必会 」贴心解析:状态管理与数据共享 InheritedWidget 完整使用方案,为你铺平大前端学习之路
圆号本昊
2021/09/24
7500
「 flutter 必知必会 」详细解析数据共享 InheritedWidget 完整使用
flutter使用eventBus进行组件间通信
在使用flutter开发过程中有些时候需要在组件之间进行通讯,我们可以借助eventBus来实现。实现步骤如下:
挥刀北上
2021/01/16
3.9K0
flutter使用eventBus进行组件间通信
Flutter完整开发实战详解(五、 深入探索)
作为系列文章的第五篇,本篇主要探索下 Flutter 中的一些有趣原理,帮助我们更好的去理解和开发。
GSYTech
2018/10/18
1.9K0
Flutter完整开发实战详解(五、 深入探索)
【Flutter】348- 写给前端工程师的 Flutter 教程
| 导语 最爱折腾的就是前端工程师了,从 jQuery 折腾到 AngularJs,再折腾到 Vue、React。最爱跨屏的也是前端工程师,从 phonegap,折腾到 React Native,这不又折腾到了 Flutter。
pingan8787
2019/09/17
1.1K0
【Flutter】348- 写给前端工程师的 Flutter 教程
Flutter完整开发实战详解(十五、全面理解State与Provider)
本篇将带你深入理解 Flutter 中 State 的工作机制,并通过对状态管理框架 Provider 解析加深理解,看完这一篇你将更轻松的理解你的 “State 大后宫” 。
GSYTech
2019/06/17
3.8K0
推荐阅读
相关推荐
Flutter完整开发实战详解(四、 Redux、主题、国际化)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验