总结
可以看出,笔者的工作学习模式便是由以下 「六个要点」 组成:
❝ 多层次的工作/学习计划 + 番茄工作法 + 定额工作法 + 批处理 + 多任务并行 + 图层工作法❞
希望大家能将这些要点融入自己的工作学习当中,我相信一定会工作与学习地更富有成效。
下面是我学习用到的一些书籍学习导图,以及系统的学习资料。每一个知识点,都有对应的导图,学习的资料,视频,面试题目。
**如:我需要学习 **Flutter的知识。(大家可以参考我的学习方法)
- Flutter 的思维导图(无论学习什么,有学习路线都会事半功倍)
- Flutter进阶学习全套手册
- Flutter进阶学习全套视频
大概就上面这几个步骤,这样学习不仅高效,而且能系统的学习新的知识。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
Flutter App的一切从 lib/main.dart
文件的main函数开始:
import ‘package:flutter/material.dart’;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: ‘Welcome to Flutter’,
home: Scaffold(
appBar: AppBar(
title: Text(‘Welcome to Flutter’),
),
body: Center(
child: Text(‘Hello World’),
),
),
);
}
}
Dart 类build方法返回的便是Widget,在Flutter中一切都是Widget,包括但不限于
-
结构性元素,menu,button等
-
样式类元素,font,color等
-
布局类元素,padding,margin等
-
导航
-
手势
Widget是Dart中特殊的类,通过实例化(Dart 中new是可选的)相互嵌套,你的这个App就是形如下图的一颗组件树(Dart入口函数的概念,main.dart -> main()
)。
Widget布局
上说过Flutter布局思路来自CSS,而Flutter中一切皆Widget,因此整体布局也很简单:
-
容器组件Container
-
decoration装饰属性,设置背景色,背景图,边框,圆角,阴影和渐变等
-
margin
-
padding
-
alignment
-
width
-
height
-
Padding,Center
-
Row,Column,Flex
-
Wrap, Flow流式布局
-
Stack, Z轴布局
-
……
Flutter中Widget可以分为三类,形如React中“展示组件”、“容器组件”,“context”。
StatelessWidget
这个就是Flutter中的“展示组件”,自身不保存状态,外部参数变化就销毁重新创建。Flutter建议尽量使用无状态的组件。
StatefulWidget
状态组件就是类似于React中的“容器组件”了,Flutter中状态组件写法会稍微不一样。
class Counter extends StatefulWidget {
// This class is the configuration for the state. It holds the
// values (in this case nothing) provided by the parent and used by the build
// method of the State. Fields in a Widget subclass are always marked “final”.
@override
_CounterState createState() => _CounterState();
}
class _CounterState extends State {
int _counter = 0;
void _increment() {
setState(() {
// This call to setState tells the Flutter framework that
// something has changed in this State, which causes it to rerun
// the build method below so that the display can reflect the
// updated values. If you change _counter without calling
// setState(), then the build method won’t be called again,
// and so nothing would appear to happen.
_counter++;
});
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance
// as done by the _increment method above.
// The Flutter framework has been optimized to make rerunning
// build methods fast, so that you can just rebuild anything that
// needs updating rather than having to individually change
// instances of widgets.
return Row(
children: [
RaisedButton(
onPressed: _increment,
child: Text(‘Increment’),
),
Text(‘Count: $_counter’),
],
);
}
}
可以看到Flutter中直接使用了和React中同名的setState
方法,不过不会有变量合并的东西,当然也有生命周期。
可以看到一个有状态的组件需要两个Class,这样写的原因在于,Flutter中Widget都是immmutable的,状态组件的状态保存在State中,组件仍然每次重新创建,Widget在这里只是一种对组件的描述,Flutter会diff转换成Element,然后转换成RenderObject才渲染。
Flutter Widget更多的渲染流程可以看 这里。
实际上Widget只是作为组件结构一种描述,还可以带来的好处是,你可以更方便的做一些主题性的组件, Flutter官方提供的Material Components widgets和Cupertino (iOS-style) widgets质量就相当高,再配合Flutter亚秒级的Hot Reload,开发体验可以说挺不错的。
State Management
setState()
可以很方便的管理组件内的数据,但是Flutter中状态同样是从上往下流转的,因此也会遇到和React中同样的问题,如果组件树太深,逐层状态创建就显得很麻烦了,更不要说代码的易读和易维护性了。
InheritedWidget
同样Flutter也有个context
一样的东西,那就是InheritedWidget
,使用起来也很简单。
class GlobalData extends InheritedWidget {
final int count;
GlobalData({Key key, this.count,Widget child}):super(key:key,child:child);
@override
bool updateShouldNotify(GlobalData oldWidget) {
return oldWidget.count != count;
}
static GlobalData of(BuildContext context) => context.inheritFromWidgetOfExactType(GlobalData);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: ‘Flutter Demo’,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: ‘Flutter Demo Home Page’),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
int _counter = 0;
void _incrementCounter() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: GlobalData(
count: _counter,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
‘You have pushed the button this many times:’,
),
Text(
‘$_counter’,
style: Theme.of(context).textTheme.display1,
),
Body(),
Body2()
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: ‘Increment’,
child: Icon(Icons.add),
),
);
}
}
class Body extends StatelessWidget {
@override
Widget build(BuildContext context) {
GlobalData globalData = GlobalData.of(context);
return Text(globalData.count.toString());
}
}
class Body2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
GlobalData globalData = GlobalData.of(context);
return Text(globalData.count.toString());
}
具体实现原理可以参考这里,不过Google封装了一个更为上层的库provider,具体使用可以看这里。
BlOC
BlOC是Flutter team提出建议的另一种更高级的数据组织方式,也是我最中意的方式。简单来说:
Bloc = InheritedWidget + RxDart(Stream)
Dart语言中内置了Steam,Stream ~= Observable,配合RxDart, 然后加上StreamBuilder
会是一种异常强大和自由的模式。
class GlobalData extends InheritedWidget {
final int count;
final Stream timeInterval$ = new Stream.periodic(Duration(seconds: 10)).map((time) => new DateTime.now().toString());
GlobalData({Key key, this.count,Widget child}):super(key:key,child:child);
@override
bool updateShouldNotify(GlobalData oldWidget) {
return oldWidget.count != count;
}
static GlobalData of(BuildContext context) => context.inheritFromWidgetOfExactType(GlobalData);
}
class TimerView extends StatelessWidget {
@override
Widget build(BuildContext context) {
GlobalData globalData = GlobalData.of(context);
return StreamBuilder(
stream: globalData.timeInterval$,
builder: (context, snapshot) {
return Text(snapshot?.data ?? ‘’);
}
);
}
}
当然Bloc的问题在于
-
学习成本略高,Rx的概念要吃透,不然你会抓狂
-
自由带来的问题是,可能代码不如Redux类的规整。
顺便,今年Apple也拥抱了响应式,Combine(Rx like) + SwiftUI 也基本等于Bloc了。
所以,Rx还是要赶紧学起来😬
除去Bloc,Flutter中还是可以使用其他的方案,譬如:
-
阿里闲鱼的Fish Redux,据说性能很好。
-
……
展开来说现在的前端开发使用强大的框架页面组装已经不是难点了。开发的难点在于如何组合富交互所需的数据,也就是上面图中的state
部分。
更具体来说,是怎么优雅,高效,易维护地处理短暂数据(ephemeral state)setState()
和需要共享的App State的问题,这是个工程性的问题,但往往也是日常开发最难的事情了,引用Redux作者Dan的一句:
“The rule of thumb is:Do whatever is less awkward.”
到这里,主要的部分已经讲完了,有这些已经可以开发出一个不错的App了。剩下的就当成一个bonus吧。
测试
Flutter debugger,测试都是出场自带,用起来也不难。
// 测试在/test/目录下面
void main() {
testWidgets(‘Counter increments smoke test’, (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(MyApp());
// Verify that our counter starts at 0.
expect(find.text(‘0’), findsOneWidget);
expect(find.text(‘1’), findsNothing);
// Tap the ‘+’ icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text(‘0’), findsNothing);
expect(find.text(‘1’), findsOneWidget);
});
}
包管理,资源管理
类似与JavaScript的npm,Flutter,也就是Dart也有自己的包仓库。不过项目包的依赖使用yaml文件来描述:
name: app
description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: “>=2.1.0 ❤️.0.0”
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
生命周期
移动应用总归需要应用级别的生命周期,flutter中使用生命周期钩子,也非常的简单:
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.inactive:
print(‘AppLifecycleState.inactive’);
break;
case AppLifecycleState.paused:
print(‘AppLifecycleState.paused’);
break;
case AppLifecycleState.resumed:
print(‘AppLifecycleState.resumed’);
break;
case AppLifecycleState.suspending:
print(‘AppLifecycleState.suspending’);
break;
}
super.didChangeAppLifecycleState(state);
}
@override
Widget build(BuildContext context) {
return Container();
}
}
使用原生能力
和ReactNative类似,Flutter也是使用类似事件的机制来使用平台相关能力。
总结
开发是面向对象。我们找工作应该更多是面向面试。哪怕进大厂真的只是去宁螺丝,但你要进去得先学会面试的时候造飞机不是么?
作者13年java转Android开发,在小厂待过,也去过华为,OPPO等,去年四月份进了阿里一直到现在。等大厂待过也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。
这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
相信它会给大家带来很多收获:
资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-nJkduXtM-1715239710686)]
总结
开发是面向对象。我们找工作应该更多是面向面试。哪怕进大厂真的只是去宁螺丝,但你要进去得先学会面试的时候造飞机不是么?
作者13年java转Android开发,在小厂待过,也去过华为,OPPO等,去年四月份进了阿里一直到现在。等大厂待过也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。
这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
相信它会给大家带来很多收获:
[外链图片转存中…(img-3DLX8BKK-1715239710686)]
[外链图片转存中…(img-5omEzG2Z-1715239710686)]
资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!