26.检测模式
原来 flutter 已经帮我们封装好了检测模式的方法了:
import 'package:flutter/foundation.dart'; if(kReleaseMode){ // release 模式该做的事 } if(kProfileMode){ // profile 模式该做的事 } if(kDebugMode){ // debug 模式该做的事情 }
看下源码:
// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /// A constant that is true if the application was compiled in release mode. /// /// More specifically, this is a constant that is true if the application was /// compiled in Dart with the '-Ddart.vm.product=true' flag. /// /// Since this is a const value, it can be used to indicate to the compiler that /// a particular block of code will not be executed in release mode, and hence /// can be removed. const bool kReleaseMode = bool.fromEnvironment('dart.vm.product', defaultValue: false); /// A constant that is true if the application was compiled in profile mode. /// /// More specifically, this is a constant that is true if the application was /// compiled in Dart with the '-Ddart.vm.profile=true' flag. /// /// Since this is a const value, it can be used to indicate to the compiler that /// a particular block of code will not be executed in profle mode, an hence /// can be removed. const bool kProfileMode = bool.fromEnvironment('dart.vm.profile', defaultValue: false); /// A constant that is true if the application was compiled in debug mode. /// /// More specifically, this is a constant that is true if the application was /// not compiled with '-Ddart.vm.product=true' and '-Ddart.vm.profile=true'. /// /// Since this is a const value, it can be used to indicate to the compiler that /// a particular block of code will not be executed in debug mode, and hence /// can be removed. const bool kDebugMode = !kReleaseMode && !kProfileMode;
源码简简单单的定义了三个常量:kReleaseMode
、kProfileMode
、kDebugMode
分别对应着 release 模式、 profile 模式、debug 模式
原理也就是对 bool.fromEnvironment() 的封装,但是少些的东西,而且还给了默认值,用它没错了。
27.断言 assert 用处
assert 只会在 debug 模式才会运行,不仅可以用来判断运行模式,还可以用来检查程序是否按要求运行。
比如:一个函数传入的参数不能为 null:
void test(String name){ assert((){ print('用户名称为空'); name!=null }()); // 其他事情 }
上面的例子是 name 是从后台获取的用户名称,但是如果没获取到 或者后台报错,那么就可以很快定位错误了。
28.数据传递的三种方案
- InheritedWidget: 适用于父组件传递给子组件的场景, 可跨层级。
- Notification:适用于子组件通知父组件数据改变的场景。
- Event Bus:事件广播,可适于于各种类型的数据通知同步。
29.直播绘制瓶颈问题
Flutter定义的 Channel 机制从本质上说是提供了ー个消息传送机制,用于图像等数据的传输,这必然会引起内存和 CPU 的巨大消耗。
解决:外接纹理 + PixelBuffer 通道传输 OpenGLES Texture 给 Skia 直接绘制。
- **节省 CPU 时间。**从我们的测试结果来看,Android 机型上ー帧 720P 的 RGBA 格式的视频,从 GPU 读取到 CPU 需要 5ms 左右,从 CPU 再传送到 GPU 又需要 5ms 左右,即使引入了 PBO,也还有 5ms 左右的耗时,这对于高帧率场景显然是不能接受的。
- **节省 CPU 内存。**数据都在 GPU 中传递,对于图片场景尤其适用,因为可能同一时间会有很多图片需要展示。
30.Sentry 异常收集
Flutter 引擎已经默认帮助我们收集了未处理异常并提供了统一处理这些异常的接口,通过给 FlutterError.onError 注册回调,这些异常就可以被手动处理,再配合 Sentry 即可实现自动地收集异常及其详细的堆栈信息。
添加 Sentry 的 Dart 版客户端 并使用 DSN 进行初始化,DSN 可以在 Sentry 面板中找到。
import 'package:sentry/sentry.dart'; final sentry = SentryClient(dsn: 'DSN');
引入 flutter/fondation
并注册回调,这些异常信息将通过 Sentry 客户端进行上传。
import 'package:flutter/foundation.dart'; ... FlutterError.onError = (e) => sentry.captureException(exception: e.exception, stackTrace: e.stack); ...
但是在开发环境下,我们通常需要直接在控制台内输出异常信息以帮助开发者快速修复问题,而不希望将它们反馈至 Sentry 。通过 DartVM 的环境变量 dart.vm.product
, 我们可以判断当前是否处于生产模式,并仅在生产模式下注册异常收集回调。
... if (bool.fromEnvironment('dart.vm.product')) FlutterError.onError = (e) => sentry.captureException(exception: e.exception, stackTrace: e.stack); ...
31.Dispose 方法注意
重写 dispose 方法并配置 AnimationController 实例。
@override dispose() { animationController.dispose(); super.dispose(); }
32.获取 Render 方法
创建 GlobalKey
GlobalKey globalKey = GlobalKey();
对应的Widget 引用 ,如这里的Text
Text('张三',key:globalKey);
通过 globalKey 来获取 对应的Element(BuildContext)
BuildContext stackContext = globalKey.currentContext;
获取对应的 RenderObject
RenderBox renderBox = stackContext.findRenderObject(); /// 相对于全局的位置 Offset offset = renderBox.localToGlobal(Offset.zero); /// 获取指定的Widget的大小 信息 Size size = renderBox.paintBounds.size;