├── .DS_Store ├── INDEX.jpeg ├── QQ.png ├── README.md ├── WECHAT.png ├── revised_1 ├── .DS_Store ├── 3-X1.png └── INDEX.md ├── revised_2 ├── 2-X1.jpg ├── 5-X1.jpg └── INDEX.md ├── revised_3 └── INDEX.md └── revised_4 └── INDEX.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/flutter_dev_book_revised/949ae431e1867cc16b1d1ce235c49a2d19625397/.DS_Store -------------------------------------------------------------------------------- /INDEX.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/flutter_dev_book_revised/949ae431e1867cc16b1d1ce235c49a2d19625397/INDEX.jpeg -------------------------------------------------------------------------------- /QQ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/flutter_dev_book_revised/949ae431e1867cc16b1d1ce235c49a2d19625397/QQ.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 《Flutter开发实战详解》修订项目 2 | 3 | #### 这个项目是用于修订补充《Flutter开发实战详解》中的一些笔误或者勘误,原纸质书可见:https://item.jd.com/12883054.html / 电子版[京东读书](https://e.jd.com/30624414.html)和[Kindle](https://www.amazon.cn/dp/B08BHQ4TKK/ref=sr_1_5?__mk_zh_CN=亚马逊网站&keywords=flutter&qid=1593498531&s=digital-text&sr=1-5) 4 | 5 | 6 | [![](./INDEX.jpeg)](https://item.jd.com/12883054.html) 7 | 8 | ### 如果图片资源看不到可以看 [码云](https://gitee.com/CarGuo/flutter_dev_book_revised) 9 | 10 | 11 | ## 修订内容 12 | 13 | - 1、[第三章中 Widget 和 Element 对应关系内容修正](./revised_1/INDEX.md) 14 | - 2、[第二章和第五章部分内容修正](./revised_2/INDEX.md) 15 | - 3、[第五章部分内容更正](./revised_3/INDEX.md) 16 | - 4、[第二章内容代码修正](./revised_4/INDEX.md) 17 | * 18 | * 19 | * 20 | * 21 | 22 | 23 | ## 联系方式 24 | 25 | ![公众号](http://img.cdn.guoshuyu.cn/wechat_qq.png) 26 | -------------------------------------------------------------------------------- /WECHAT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/flutter_dev_book_revised/949ae431e1867cc16b1d1ce235c49a2d19625397/WECHAT.png -------------------------------------------------------------------------------- /revised_1/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/flutter_dev_book_revised/949ae431e1867cc16b1d1ce235c49a2d19625397/revised_1/.DS_Store -------------------------------------------------------------------------------- /revised_1/3-X1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/flutter_dev_book_revised/949ae431e1867cc16b1d1ce235c49a2d19625397/revised_1/3-X1.png -------------------------------------------------------------------------------- /revised_1/INDEX.md: -------------------------------------------------------------------------------- 1 | > **在 70 页说中介绍了 Widget 和 Element 是多对一的关系,但是在 88 页又说是一对多的关系,该怎么理解?** 2 | 3 | 这里补充解释下,避免读者混乱: 4 | 5 | 在 70 页里因为一开始在解释 Widget 和 Element 的时候,是从实例的角度去做对比,因为 Widget 是不可变的,所以在 Widget 不断被更新的整个历史周期里,多个 Widget 实例在绘制过程会被用到一个 Element,所以是多对一的关系,这样也是比较好理解的。 6 | 7 | 8 | 而到 88 页的时候是把 Widget 定位成了配置文件的角度,一个已经存在的配置文件(Widget)被多个 Element 所引用。如下图所示,正如官方在注释里说,Widget 是 Element 的配置文件,Element 通过 Widget 去配置 RenderObject 实现更新绘制。 9 | 10 | 11 | ![](./3-X1.png) 12 | 13 | 所以该角度 Widget 和 Element 是一对多的关系,因为真实工作的其实是 Element 树,而 Widget 作为配置文件,可能会在多个地方被复用,就如注释中的 : 14 | 15 | > a given widget can be placed in the tree multiple times. Each time a widget is placed in the tree, it is inflated into an [Element] 16 | 17 | 18 | 举一个不是十分严格但是很具代表性的例子,如下代码所示,通过运行如下代码后,可以看到 `textUseAll` 在多个地方被 inflated 并且正常渲染出`3333333` 的效果。 19 | 20 | ```dart 21 | 22 | final textUseAll = new Text( 23 | "3333333", 24 | style: new TextStyle(fontSize: 18, color: Colors.red), 25 | ); 26 | 27 | class MyHomePage extends StatelessWidget { 28 | void goNext(context) { 29 | Navigator.of(context).push(MaterialPageRoute(builder: (context) { 30 | return ShowPage(); 31 | })); 32 | } 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return Scaffold( 37 | appBar: AppBar(), 38 | body: Center( 39 | child: Container( 40 | color: Colors.blue, 41 | height: 80, 42 | child: Stack( 43 | children: [ 44 | new Center( 45 | child: Row( 46 | crossAxisAlignment: CrossAxisAlignment.center, 47 | textBaseline: TextBaseline.alphabetic, 48 | mainAxisAlignment: MainAxisAlignment.center, 49 | children: [ 50 | textUseAll, 51 | Text( 52 | ' GSY ', 53 | style: TextStyle(fontSize: 36, fontFamily: "Heiti"), 54 | ), 55 | textUseAll, 56 | ], 57 | ), 58 | ), 59 | ], 60 | ), 61 | )), 62 | floatingActionButton: FloatingActionButton( 63 | onPressed: () { 64 | goNext(context); 65 | }, 66 | tooltip: 'Next', 67 | child: Icon(Icons.add), 68 | ), 69 | ); 70 | } 71 | } 72 | 73 | class ShowPage extends StatelessWidget { 74 | void goNext(context) { 75 | Navigator.of(context).push(MaterialPageRoute(builder: (context) { 76 | return ShowPage(); 77 | })); 78 | } 79 | 80 | @override 81 | Widget build(BuildContext context) { 82 | return Scaffold( 83 | appBar: AppBar(), 84 | body: Container( 85 | child: new Center( 86 | child: 87 | textUseAll, 88 | ), 89 | ), 90 | floatingActionButton: FloatingActionButton( 91 | onPressed: () { 92 | goNext(context); 93 | }, 94 | tooltip: 'goNext', 95 | child: Icon(Icons.add), 96 | ), 97 | ); 98 | } 99 | } 100 | 101 | ``` 102 | 103 | **所以造成该笔误的原因是前后角度出现变化,故此更正。** 104 | -------------------------------------------------------------------------------- /revised_2/2-X1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/flutter_dev_book_revised/949ae431e1867cc16b1d1ce235c49a2d19625397/revised_2/2-X1.jpg -------------------------------------------------------------------------------- /revised_2/5-X1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CarGuo/flutter_dev_book_revised/949ae431e1867cc16b1d1ce235c49a2d19625397/revised_2/5-X1.jpg -------------------------------------------------------------------------------- /revised_2/INDEX.md: -------------------------------------------------------------------------------- 1 | ## 第二章本次订正内容 2 | 3 | ![](./2-X1.jpg) 4 | 5 | 6 | 如上图所示,在 34 页的 Class A 对象内 super.a() 方法注释了,如下所示输出结果,按照书中所示的执行结果,这里的 super.a() 不能屏蔽,因为屏蔽之后 B.a() 和 base a() 不会执行输出。 7 | 8 | 9 | ``` 10 | flutter: A2.a() 11 | flutter: A.a() 12 | flutter: B.a() 13 | flutter: base a() 14 | flutter: A.b() 15 | flutter: B.b() 16 | flutter: base b() 17 | flutter: B.c() 18 | flutter: base c() 19 | ``` 20 | 21 | 但是此处逻辑是为了对比 mixin 的行为结果,所以这里按照 Class A 对象内 super.a() 方法注释,那么输出结果应该是如下所示: B.a() 和 base a() 没有输出,故此处代码的输出结果应修改为如下所示: 22 | 23 | ``` 24 | flutter: A2.a() 25 | flutter: A.a() 26 | flutter: A.b() 27 | flutter: B.b() 28 | flutter: base b() 29 | flutter: B.c() 30 | flutter: base c() 31 | ``` 32 | 33 | 后续解释应修改为 34 | 35 | 从最终输出结果可以看到: 36 | 37 | - 在执行 g.a() 方法时,输出的是从入最右边的 A2.a() 开始的,之后才是 A.a() ,**而B.a()、base a() 没有被执行,因为 Class A 对象内 super.a() 方法注释;** 38 | - 在执行 g.b() 方法时,因为 A2 没有 b() 方法存在,所以按照顺序只输出了 A.b()、B.b()、 base b(); 39 | - 在执行 g.c() 方法时,因为 A2 和 A 都没有实现 c 方法,所以只输出了 B.c() 、base c()。 40 | 41 | 42 | **另外需要额外补充说明,如果你在运行代码出现如下所示问题:** 43 | 44 | ``` 45 | error: The class 'A2' can't be used as a mixin because it extends a class other than Object. 46 | ``` 47 | 48 | 那么需要在你**项目根目录增加 analysis_options.yaml 文件,并添加如下所示内容后执行`flutter pub get`。** 49 | 50 | 51 | ``` 52 | analyzer: 53 | errors: 54 | mixin_inherits_from_not_object: ignore 55 | mixin_references_super: ignore 56 | ``` 57 | 58 | 如果是低版本 dart analysis_options.yaml 需添加内容应增加为如下所示: 59 | 60 | ``` 61 | analyzer: 62 | language: 63 | enableSuperMixins: true 64 | errors: 65 | mixin_inherits_from_not_object: ignore 66 | mixin_references_super: ignore 67 | ``` 68 | 69 | 70 | 71 | ## 第五章本次订正内容 72 | 73 | 74 | ![](./5-X1.jpg) 75 | 76 | 如上图所示,在 187 页上这里的内容应该是 index == 1 ,也就是代码注释里写的第二个 Item,在这里订正。 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /revised_3/INDEX.md: -------------------------------------------------------------------------------- 1 | 书中142页: 2 | 3 | > “在 Android 和 iOS 上,Flutter Engine 会为 UI Task Runner、GPU Task Runner 和 I/O Task Runner 各自创建一个独立的线程,而所有 Engine 实例会共享同一个 Platform Task Runner 线程,对于平台而言,Platform Task Runner 就是平台的主线程,Fuchsia 和 Web 不一样” 4 | 5 | 而在139页: 6 | 7 | > Flutter Engine 自己并不创建和管理线程,线程的创建和管理是由 Embedder 层负责。 8 | 9 | 这里同样是主体对象没区分开导致,其实大多数时候我们讨论 Engine 都会默认把 Engine 和 Embedder 作为一个底层整体: 10 | 11 | - 139页开篇时是把整个 Flutter Framework 拆分为多层解释,单独把 Skia 所在的 C++ 层作为 Engine 来理解,是为了更好的介绍 Flutter 内的分层结构; 12 | - 142页其实是已经把整个 Engine(C++) 和 Embedder 作为一个整体 Engine 对待,所以这里产生了歧义。 13 | 14 | 15 | 考虑到这个歧义,在 142 页这里应该可以把 Engine 去掉,并且把创建改为分配更恰当: 16 | 17 | > “在 Android 和 iOS 上,Flutter 会为 UI Task Runner、GPU Task Runner 和 I/O Task Runner 各自分配一个独立的线程,而所有 Engine 实例会共享同一个 Platform Task Runner,对于平台而言,Platform Task Runner 就是平台的主线程,Fuchsia 和 Web 不一样” 18 | 19 | 是的,在 Flutter 中可以创建多个 Engine。 20 | 21 | 另外文章的后面也介绍了,Runner 和线程没有绝对关系,只是 Android 和 iOS 平台上的默认行为是为这四个默认 Runner 各自分配了一个独立线程,所以结合起来理解应该不会有太大问题。 22 | 23 | > ps: 1.17 版本开始,底层绘制上 Android 可能会用到 Vulkan,而 iOS 可能会是 Metal,这主要和硬件还有系统版本有关系。 24 | -------------------------------------------------------------------------------- /revised_4/INDEX.md: -------------------------------------------------------------------------------- 1 | 2.4.6 懒加载部分代码 2 | 3 | `getNetworkData` 方法增加 `Future` 的声明,`Text`使用 `data.data` 。 4 | 5 | 6 | 7 | ``` 8 | class SampleFutureBuilder extends StatelessWidget { 9 | Future getNetworkData() async { 10 | await Future.delayed(Duration(seconds: 10)); 11 | return "result"; 12 | } 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return FutureBuilder( 17 | future: getNetworkData(), 18 | initialData: "init", 19 | builder: (BuildContext context, AsyncSnapshot data) { 20 | return Container( 21 | child: new Text(data.data ?? "loading"), 22 | ); 23 | }); 24 | } 25 | } 26 | 27 | ``` 28 | 29 | 30 | --------------------------------------------------------------------------------