Google同学推荐-编写高质量Flutter代码的50个有效方法

432 阅读8分钟

当编写高质量的Flutter代码时,以下每个方法都附有详细的代码示例。代码示例中将包括高效和普通对比示例。

1. 使用有意义的变量和方法命名

// 不好的示例
var a = 10;
var b = calculate(a);

// 好的示例
var initialNumber = 10;
var calculatedResult = calculate(initialNumber);

2. 使用const关键字来定义不可变对象

// 不好的示例
final myNumber = new MyNumber();

// 好的示例
const myNumber = MyNumber();

3. 遵循Dart代码风格指南

// 不好的示例
int result=calculate(5);

// 好的示例
int calculate(int number) {
  // code here
  return result;
}

4. 使用async/await处理异步任务

// 不好的示例
http.get('https://example.com').then((response) {
  print(response.body);
});

// 好的示例
void fetchData() async {
  var response = await http.get('https://example.com');
  print(response.body);
}

5. 使用正确的数据类型

// 不好的示例
var count = "10";

// 好的示例
int count = 10;

6. 减少widget的build方法中的逻辑

// 不好的示例
Widget build(BuildContext context) {
  if (condition1) {
    // code here
  } else if (condition2) {
    // code here
  } else {
    // code here
  }
}

// 好的示例
Widget build(BuildContext context) {
  if (condition1) {
    return Widget1();
  }
  if (condition2) {
    return Widget2();
  }
  return Widget3();
}

7. 使用keys来优化列表操作

// 不好的示例
List<Widget> buildList() {
  var items = <Widget>[];
  for (var i = 0; i < data.length; i++) {
    items.add(Widget(item: data[i]));
  }
  return items;
}

// 好的示例
List<Widget> buildList() {
  return data.map((item) => Widget(item: item)).toList();
}

8. 使用Builder构建局部刷新widget

// 不好的示例
Widget build(BuildContext context) {
  return Container(
    child: SomeWidget(),
  );
}

// 好的示例
Widget build(BuildContext context) {
  return Container(
    child: Builder(
      builder: (context) => SomeWidget(),
    ),
  );
}

9. 使用Expanded或Flexible来管理布局

// 不好的示例
Row(
  children: [
    Widget1(),
    Widget2(),
    Widget3(),
  ],
);

// 好的示例
Row(
  children: [
    Expanded(child: Widget1()),
    Expanded(child: Widget2()),
    Widget3(),
  ],
);

10. 使用Keys来在列表中标识唯一性

// 不好的示例
ListView.builder(
  itemCount: data.length,
  itemBuilder: (context, index) {
    return Widget(data: data[index]);
  },
);

// 好的示例
ListView.builder(
  itemCount: data.length,
  itemBuilder: (context, index) {
    return Widget(
      key: Key(data[index].id),
      data: data[index],
    );
  },
);

11. 使用函数式编程来简化代码

// 不好的示例
for (var item in list) {
  if (item.condition) {
    item.process();
  }
}

// 好的示例
list.where((item) => item.condition).forEach((item) => item.process());

12. 使用继承或混入来重用代码

// 不好的示例
class MyWidget1 extends StatelessWidget {
  // code here
}

class MyWidget2 extends StatelessWidget {
  // code here
}

// 好的示例
class BaseWidget extends StatelessWidget {
  // code here
}

class MyWidget1 extends BaseWidget {
  // code here
}

class MyWidget2 extends BaseWidget {
  // code here
}

13. 避免在build方法中进行重复计算

// 不好的示例
Widget build(BuildContext context) {
  var result = calculateResult(); // 假设计算耗时较长
  return Text(result.toString());
}

// 好的示例
Widget build(BuildContext context) {
  var result = useMemoizedResult(() => calculateResult());
  return Text(result.toString());
}

14. 使用函数回调处理用户交互

// 不好的示例
void onButtonPressed() {
  // code here
}

Widget build(BuildContext context) {
  return RaisedButton(
    onPressed: onButtonPressed(),
    child: Text('Button'),
  );
}

// 好的示例
void onButtonPressed() {
  // code here
}

Widget build(BuildContext context) {
  return RaisedButton(
    onPressed: onButtonPressed,
    child: Text('Button'),
  );
}

15. 及时释放资源

// 不好的示例
void fetchData() async {
  var httpClient = HttpClient();
  // code here
}

// 好的示例
void fetchData() async {
  var httpClient = HttpClient();
  try {
    // code here
  } finally {
    httpClient.close(); // 及时关闭
  }
}

16. 封装常用的UI组件

// 不好的示例
Widget build(BuildContext context) {
  return Container(
    width: MediaQuery.of(context).size.width,
    height: MediaQuery.of(context).size.height,
    // code here
  );
}

// 好的示例
Widget build(BuildContext context) {
  return FullScreenContainer(
    // code here
  );
}

class FullScreenContainer extends StatelessWidget {
  final Widget child;

  const FullScreenContainer({Key key, this.child}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: MediaQuery.of(context).size.width,
      height: MediaQuery.of(context).size.height,
      child: child,
    );
  }
}

17. 使用List.generate构建动态列表

// 不好的示例
ListView.builder(
  itemCount: data.length,
  itemBuilder: (context, index) {
    return Widget(item: data[index]);
  },
);

// 好的示例
ListView(
  children: List.generate(data.length, (index) {
    return Widget(item: data[index]);
  }),
);

18. 使用带默认值的构造函数

// 不好的示例
class Person {
  final String name;
  final String age;

  Person({this.name, this.age});
}

var person = Person(name: 'John');

// 好的示例
class Person {
  final String name;
  final String age;

  Person({this.name, this.age = ''});
}

var person = Person(name: 'John');

19. 使用Dart的强类型系统

// 不好的示例
Map data = jsonDecode(response.body);

// 好的示例
Map<String, dynamic> data = jsonDecode(response.body);

20. 隔离和重用样式

// 不好的示例
Text(
  'Hello',
  style: TextStyle(
    color: Colors.red,
    fontSize: 16,
    fontWeight: FontWeight.bold,
  ),
);

// 好的示例
Text(
  'Hello',
  style: myTextStyle,
);

final myTextStyle = TextStyle(
  color: Colors.red,
  fontSize: 16,
  fontWeight: FontWeight.bold,
);

21. 使用扩展方法增强现有类

// 不好的示例
String capitalize(String input) {
  return input[0].toUpperCase() + input.substring(1);
}

var name = capitalize('john');

// 好的示例
extension StringExtension on String {
  String capitalize() {
    return this[0].toUpperCase() + substring(1);
  }
}

var name = 'john'.capitalize();

22. 使用final和const关键字声明常量

// 不好的示例
var PI = 3.14;

// 好的示例
final double PI = 3.14;

23. 使用导航器管理页面路由

// 不好的示例
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondPage()),
);

// 好的示例
Navigator.pushNamed(context, '/second');

24. 使用Mixin实现代码重用

// 不好的示例
class MyWidget1 extends StatelessWidget {
  // code here
}

class MyWidget2 extends StatelessWidget {
  // code here
}

// 好的示例
mixin CommonMixin {
  // common code here
}

class MyWidget1 extends StatelessWidget with CommonMixin {
  // code here
}

class MyWidget2 extends StatelessWidget with CommonMixin {
  // code here
}

25. 使用Builder分离复杂的UI构建逻辑

// 不好的示例
Widget build(BuildContext context) {
  return Container(
    child: Column(
      children: [
        SomeWidget(),
        AnotherWidget(),
      ],
    ),
  );
}

// 好的示例
Widget build(BuildContext context) {
  return Container(
    child: Builder(
      builder: (context) {
        return Column(
          children: [
            SomeWidget(),
            AnotherWidget(),
          ],
        );
      },
    ),
  );
}

26. 使用默认参数简化方法调用

// 不好的示例
void printMessage(String message, {String prefix = '', String suffix = ''}) {
  print(prefix + message + suffix);
}

printMessage('Hello', prefix: '[', suffix: ']');

// 好的示例
void printMessage(String message, {String prefix = '', String suffix = ''}) {
  print(prefix + message + suffix);
}

printMessage('Hello', prefix: '[', suffix: ']');

27. 使用适当的状态管理方案

// 不好的示例
class MyApp extends StatelessWidget {
  final String data;

  MyApp({Key key, this.data}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text(data);
  }
}

// 好的示例
class MyApp extends StatefulWidget {
  final String data;

  MyApp({Key key, this.data}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return Text(widget.data);
  }
}

28. 使用闭包进行私有变量封装

// 不好的示例
class Counter {
  var count = 0;
  
  void increment() {
    count++;
  }
  
  void decrement() {
    count--;
  }
}

// 好的示例
class Counter {
  int count = 0;
  
  void Function() get increment {
    return () {
      count++;
    };
  }
  
  void Function() get decrement {
    return () {
      count--;
    };
  }
}

29. 使用自定义Painter创建自定义UI

// 不好的示例
Widget build(BuildContext context) {
  return Container(
    color: Colors.blue,
    child: CustomPaint(
      painter: MyPainter(),
      child: Container(),
    ),
  );
}

class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    // code here
  }

  @override
  bool shouldRepaint(MyPainter oldDelegate) => true;
}

// 好的示例
Widget build(BuildContext context) {
  return Container(
    color: Colors.blue,
    child: CustomPaint(
      painter: MyPainter(),
    ),
  );
}

class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    // code here
  }

  @override
  bool shouldRepaint(MyPainter oldDelegate) => false;
}

30. 使用位操作来处理多选状态

// 不好的示例
bool option1Selected = false;
bool option2Selected = false;

void toggleOption1() {
  option1Selected = !option1Selected;
}

void toggleOption2() {
  option2Selected = !option2Selected;
}

// 好的示例
int options = 0;

void toggleOption(int option) {
  options ^= (1 << option);
}

bool isOptionSelected(int option) {
  return (options & (1 << option)) != 0;
}

31. 使用FutureBuilder处理异步数据

// 不好的示例
Widget build(BuildContext context) {
  return FutureBuilder(
    future: fetchData(),
    builder: (context, snapshot) {
      if (snapshot.connectionState == ConnectionState.done) {
        return Text(snapshot.data.toString());
      }
      return CircularProgressIndicator();
    },
  );
}

// 好的示例
Widget build(BuildContext context) {
  return FutureBuilder(
    future: fetchData(),
    builder: (context, snapshot) {
      if (snapshot.connectionState == ConnectionState.done) {
        if (snapshot.hasData) {
          return Text(snapshot.data.toString());
        }
        return Text('No data');
      }
      return CircularProgressIndicator();
    },
  );
}

32. 使用Clipper创建自定义的剪切区域

// 不好的示例
Widget build(BuildContext context) {
  return ClipRRect(
    borderRadius: BorderRadius.circular(10),
    child: Container(
      // code here
    ),
  );
}

// 好的示例
Widget build(BuildContext context) {
  return ClipPath(
    clipper: MyClipper(),
    child: Container(
      // code here
    ),
  );
}

class MyClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    // code here
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}

33. 使用Hero动画创建过渡效果

// 不好的示例
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondPage()),
);

// 好的示例
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => HeroPage()),
);

class HeroPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Hero(
        tag: 'image',
        child: Image.asset('image.png'),
      ),
    );
  }
}

34. 使用InheritedWidget来共享数据

// 不好的示例
class MyApp extends StatelessWidget {
  final String title;

  MyApp(this.title);

  @override
  Widget build(BuildContext context) {
    return Text(title);
  }
}

// 好的示例
class MyApp extends StatelessWidget {
  final String title;

  MyApp(this.title);

  @override
  Widget build(BuildContext context) {
    return InheritedTitle(
      title: title,
      child: Text(title),
    );
  }
}

class InheritedTitle extends InheritedWidget {
  final String title;

  InheritedTitle({Key key, @required this.title, @required Widget child})
      : super(key: key, child: child);

  @override
  bool updateShouldNotify(InheritedTitle oldWidget) => title != oldWidget.title;
}

35. 使用SingleTickerProviderStateMixin管理动画控制器

// 不好的示例
class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      duration: Duration(seconds: 1),
      vsync: this, // 需要手动指定vsync参数
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

// 好的示例
class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> with SingleTickerProviderStateMixin {
  AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      duration: Duration(seconds: 1),
      vsync: this, // 自动使用当前State作为vsync
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

36. 遵循命名规范: 使用一致的命名约定,以增加代码的可读性和可维护性。例如,使用驼峰式命名法CamelCase来命名类和方法,使用小写字母和下划线来命名变量和函数。

// 不良示例
var c = Container();

// 良好示例
var container = Container();

37. 减少小部件的重建: 尽可能使用const修饰符创建不可变小部件,以减少不必要的小部件重建,提高性能。

// 不良示例
Widget build(BuildContext context) {
  return Text('Hello World');
}

// 良好示例
Widget build(BuildContext context) {
  return const Text('Hello World');
}

38. 使用关键字:nnn进行空安全声明: 在声明变量时,使用空安全的关键字?!,以帮助在编译时捕获空引用错误。

// 不良示例
String name;

// 良好示例
String? name;

39. 使用类型推断: 让Dart自动推断变量的类型,以减少不必要的类型注释,使代码更简洁。

// 不良示例
List<String> fruits = [];

// 良好示例
var fruits = <String>[];

40. 使用finalconst进行不可变声明: 标记不需要修改的变量为finalconst,以提醒自己和其他开发人员该变量的不可变性。

// 不良示例
var name = 'John';
name = 'Mike'; // 可修改

// 良好示例
final name = 'John';
const age = 25;

41. 避免冗余的小部件嵌套: 最小化小部件的嵌套层次,以提高代码的清晰度和执行效率。

// 不良示例
Column(
  children: [
    Container(
      child: Row(
        children: [
          Text('Hello World'),
        ],
      ),
    ),
  ],
)

// 良好示例
Row(
  children: [
    Text('Hello World'),
  ],
)

42. 使用Key标识唯一小部件: 当列表中的小部件需要更新时,为它们分配唯一的Key,以确保正确的渲染和状态更新。

// 不良示例
ListView.builder(
  itemBuilder: (context, index) => Text('Item'),
)

// 良好示例
ListView.builder(
  itemBuilder: (context, index) => Text('Item', key: Key('$index')),
)

43. 使用asyncawait处理异步任务: 使用asyncawait关键字来优雅地处理异步任务,提高代码的可读性。

// 不良示例(回调风格)
fetchData((data) {
  processData(data, (result) {
    setState(() {
      this.result = result;
    });
  });
});

// 良好示例(async/await风格)
final data = await fetchData();
final result = processData(data);
setState(() {
  this.result = result;
});

44. 处理小部件生命周期: 当使用有状态小部件时,妥善处理生命周期方法,避免出现内存泄漏或不必要的资源消耗。

@override
void dispose() {
  _controller.dispose();
  super.dispose();
}

45. 抽象常用样式为主题: 使用Theme小部件将常用的样式属性抽象为主题数据,以便在应用程序中共享和重复使用。

```dart
// 不良示例
Text('Hello World', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold))

// 良好示例
Text('Hello World', style: Theme.of(context).textTheme.headline6)
```

46. 避免在构建方法中执行昂贵的操作: 在构建方法中尽量避免执行耗时或昂贵的操作,以避免影响性能。

```dart
// 不良示例
Widget build(BuildContext context) {
  final result = fetchData(); // 昂贵的操作

  return Text('Result: $result');
}

// 良好示例
Widget build(BuildContext context) {
  return FutureBuilder(
    future: fetchData(),
    builder: (context, snapshot) {
      if (snapshot.hasData) {
        return Text('Result: ${snapshot.data}');
      }
      return CircularProgressIndicator();
    },
  );
}
```

47. 使用final替代var: 在可能的情况下,使用final关键字而不是var关键字声明变量,以提高代码的可读性。

```dart
// 不良示例
var fruits = <String>[];

// 良好示例
final fruits = <String>[];
```

48. 封装经常使用的小部件: 创建自定义小部件来封装经常使用的复杂小部件,以提高代码的重用性和可维护性。

```dart
class CustomButton extends StatelessWidget {
  final String text;
  final VoidCallback onPressed;

  const CustomButton({required this.text, required this.onPressed});

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(text),
    );
  }
}
```

49. 使用builder构造器简化小部件树: 使用builder构造器来简化小部件树的构建,减少嵌套。

```dart
// 不良示例
Widget build(BuildContext context) {
  return Container(
    child: Padding(
      child: Text('Hello World'),
      padding: EdgeInsets.all(16),
    ),
  );
}

// 良好示例
Widget build(BuildContext context) {
  return Container(
    child: Builder(
      builder: (context) {
        return Padding(
          padding: EdgeInsets.all(16),
          child: Text('Hello World'),
        );
      },
    ),
  );
}
```

50. 使用enum管理状态: 使用enum集中管理各种状态,以减少硬编码的同时提高代码可读性。

```dart
enum ViewState { idle, loading, error, success }

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  ViewState _state = ViewState.idle;

  @override
  Widget build(BuildContext context) {
    if (_state == ViewState.loading) {
      return CircularProgressIndicator();
    } else if (_state == ViewState.error) {
      return Text('Error occurred.');
    } else if (_state == ViewState.success) {
      return Text('Success!');
    }
    return Text('Idle');
  }
}
```