在有状态的 StatefulWidget中,build 方法会重复调用两次,所有如果在build 方法中使用 FutureBuilder 这种延迟加载控件【即先获取网络或者本地数据,然后再去创建Widget的组件】,future 对象不能在构造方法中进行调用,而是应该放在 initState 方法中进行。
@override void initState() { _future = _loadDefaultData(); //这么写,避免重复调用两次 super.initState(); } Future
判断当前App是否以 releaseMode 模型运行
print("kReleaseMode $kReleaseMode");
3、自建 Flutter 系统错误处理框架自建的Flutter 系统错误处理框架
//run(Widget app){...}//框架异常 即Flutter 框架自生所产生的Error,不是我们的代码产生的ErrorFlutterError.onError = (FlutterErrorDetails details) async { //线上环境,走上报逻辑 if (kReleaseMode){ Zone.current.handleUncaughtError(details.exception, details.stack); } else { //开发期间,走console 抛出 FlutterError.dumpErrorToConsole(details); }};
处理自己写出的错误框架
runZonedGuarded(() { runApp(app);}, (e, s){ //print('HiZone $e'); _reportError(e, s);});//通过接口上报异常信息_reportError(Object error, StackTrace s){ print("kReleaseMode $kReleaseMode"); print("object $error");//可以自己搭建一个错误处理框架}
总的代码如下:
import 'dart:async';import 'package:flutter/cupertino.dart';import 'package:flutter/foundation.dart';import 'package:flutter/material.dart';class HiZone { run(Widget app) { //框架异常 即Flutter 框架自生所产生的Error,不是我们的代码产生的Error FlutterError.onError = (FlutterErrorDetails details) async { //线上环境,走上报逻辑 if (kReleaseMode){ Zone.current.handleUncaughtError(details.exception, details.stack); } else { //开发期间,走console 抛出 FlutterError.dumpErrorToConsole(details); } }; runZonedGuarded(() { runApp(app); }, (e, s){ //print('HiZone $e'); _reportError(e, s); }); } //通过接口上报异常信息 _reportError(Object error, StackTrace s){ print("kReleaseMode $kReleaseMode"); print("object $error"); }}
4、Flutter 接口Flutter 中接口和抽象类类似,都是用 abstract 关键字来标明
//弹幕组件abstract class IBarrage { //发送弹幕消息 void send(String message); //暂停 void pause(); //播放弹幕消息 void play();}
5、Flutter 中 typedef 的使用typedef 的用法有点类似Java中的接口,但是Java接口中的是例如 xxInterface.on(data),这种写法,而Flutter中是直接 xxxCallback(data) 这种形式来callback,感觉认为函数也是一等公民,可以直接作为引用直接调用,也可以直接作为参数传递。
class NetError { final int statusCode; final String message; NetError(this.statusCode, this.message);}typedef NetErrorCallback(NetError netError);class HttpRequest { void sendRequest() { Future.delayed(Duration(seconds: 1), (){ try { if (callback!=null) { callback(NetError(101, '发生未知错误')); } return 10+11; } catch (e) { throw Exception(e); } }).then((value) => print(value)).onError((error, stackTrace) => print(error)); } NetErrorCallback callback; void addNetErrorCallback(NetErrorCallback callback){ this.callback = callback; }}//使用var httpRequest = HttpRequest();httpRequest.addNetErrorCallback((netError) => print(netError.message));httpRequest.sendRequest();
6、函数类型的参数void doFunction(int doAdd(int age), int num){ int result = doAdd(num); print("doAdd result is $result");}void main() { print("hello "); int add(int count){ return 10+count; } doFunction(add, 100); doFunction((age) => 12+age, 100);}
7、Flutter 设置图片缓存Flutter 应该是没有磁盘缓存,只有内存缓存,所以为了提高图片加载的效率,需要设置图片缓存的大小。
//在初始化偏好设置的init方法中调用如下代码//图片缓存大小设置//image_cache.dart//const int _kDefaultSize = 1000;//const int _kDefaultSizeBytes = 100 << 20; // 100 MiBPaintingBinding.instance.imageCache.maximumSize = 2000; //默认是1000张图片 现在改成2000张PaintingBinding.instance.imageCache.maximumSizeBytes = 200 << 20; //改成200M
8、关于多层次异步任务调用void main() { doBusiness() async { int result = await Business.sleep(); //因为sleep方法返回的是Future类型的,所以要使用await来等待并获取返回值,同时用async来标记方法 print("result is $result"); } //另外,从该例子中学习到了,只要Dart中还有异步任务[事件任务,不是微任务],那么就不会结束进程,休息了5秒之后,才回结束掉进程 doBusiness(); //这里执行的是异步任务,不会阻塞主线程,但是不同与Java中的异步任务,Java是多线程,Dart是单线程,异步是基于事件任务队列执行的 print("main线程结束...");}class Business { static sleep(){ //返回的数据类型是Future类型的 return doSomeSleep(); } static doSomeSleep() async{ //async 标记该方法是异步任务,返回的数据是Future类型的 await Future.delayed(Duration(seconds: 5)); return 100; // }}
9、Positioned 组件的使用//positioned widget 用于在Stack控件中定位位置,left, right, bottom, top stack( children:[ Positioned( left:0, right:0, bottom:0, chiild:Container(...), ), ..、 ])
10、渐变色 LinearGradient//在Container中利用decoration来添加渐变色decoration: BoxDecoration ( //渐变 gradient: LinearGradient ( begin: Alignment.bottomCenter, //渐变色开始的位置 end: Alignment.topCenter,//渐变色结束的位置 colors: [Colors.black54, Colors.transparent]//分别对应开始和结束位置的颜色 ))
11、ScrollController 的使用ScrollController scrollController = ScrollController();scrollController.addListener(() { // maxScrollExtent 最大的可滚动距离 pixels 是当前的已经滚动距离 // dis = _scrollController.position.maxScrollExtent - _scrollController.position.pixels // 当前距离页面底部还有剩余多少距离 // 怎么看 pixels 这个参数呢? // 可以这么看,就是顶部控件超过顶部这条线到距离大小是多少,然后用总到大小减去就是剩余底部的距离 var dis = scrollController.position.maxScrollExtent - scrollController.position.pixels; if ( dis < 200 && !isLoadingMore && scrollController.position.maxScrollExtent!=0 && scrollController.position.pixels>0) { print('dis $dis position.pixels ${scrollController.position.pixels}'); loadData(loadMore: true);//开始加载更多 }});
12、const widget 常量Widget1、利用 const 构造无状态Widget
class ChildWidget extends StatelessWidget { final String myText; const ChildWidget(this.myText, {Key key}) : super(key: key); @override Widget build(BuildContext context) { return Container( child: Text(myText), ); }}
2、在父Widget 中的 State 中使用 ChildWidget
class ParentWidget extends StatefulWidget { const ParentWidget({Key key}) : super(key: key); @override _ParentWidgetState createState() => _ParentWidgetState();}class _ParentWidgetState extends State
3、const Widget 的优势
首先总结下,const 在Dart 语言中特点:
1、一个Dart 类的对象是否能用 const 修饰,取决于类的构造方法是否被 const 修饰;
2、使用const 修饰的构造方法中,所有的成员变量必须被 final 修饰;
3、构造 const 对象时,传参也必须是 const 的常量;
4、const 修饰的构造方法,不能有方法体;
对于Flutter来说,const 修饰的优化点:
利用常量池复用 Widget,在更新频繁的 Widget 场景中,有优化作用,避免了 Widget 的回收和重建;const 对GC 有一定的抑制作用,在创建大量相同对象的场景下,创建的对象少了,自然GC也会变少。
const 对GC的优化
在Flutter 中,Widget 作为配置信息,本身被设计的非常轻量,就是为了适应频繁的销毁重建,这个操作必然会引起对旧 Widget 对象的回收。
当我们使用 const 关键字声明常量的时候,背后是利用的类似常量池的概念,将 const 的对象缓存在常量池中,以待后续复用。
常量会具备普通对象更长的生命周期,这有好处也有坏处。好处就是常量对象会对 GC不那么敏感,也就是不需要频繁的触发GC。坏处是常量池中的生命周期较长,可能会导致不常用的对象被缓存后,没有适合释放时机,导致内存占用过高。
实测下来,const 确实对 GC 有一些影响。
13、Flutter 中 function 和 method 区别
Flutter 中function 和 method 是有区别的,function 表示一个功能,可以独立使用,是一等公民,而 method 不能单独使用,必须由类的实例来进行调用。
14、强制改变屏幕方向dependencies: orientation: ^1.2.0//使用OrientationPlugin.forceOrientation(DeviceOrientation.portraitUp);
15、属性扩展enum RouteStatus {homePage, videoListPage, videoDetailPage, loginPage, registrationPage, unknownPage}//给枚举扩展属性extension RouteStatusExtension on RouteStatus{ String get name => ['homePage', 'videoListPage', 'videoDetailPage','loginPage','registrationPage','unknownPage'][index];}
16、创建Model类在AndroidStudio中使用JsonToDart插件,在创建好xx_moel.dart 文件之后,在文件空白地方,右键 generate -> jsonToDart, 贴入json字符串就可以生成对应的model类。
17、操作符// A?.B 如果A为null, 那么A?.B 返回的就是null 反之 如果A不为null, 那么A?.B的就是A.B// A??B 如果A为null, 那么A??B 返回的就是B 否则就是不做任何处理 返回的就是A
18、ViewPortViewPort 可以大于屏幕高度,也可以小于屏幕高度,是确定可滚动范围使用的。