Flutter 注解开发:轻松愉快地探索注解之旅
本文将带您轻松愉快地探索 Flutter 中注解的开发。我们将通过以下小节展开这次有趣的旅程。
[TOC]
一、 介绍背景:开启神奇的注解之旅
相信在日常开发过程中,我们经常会面临以下挑战:大量重复的模板代码、臃肿的代码降低可读性,以及JSON序列化和反序列化问题。为应对这些问题,各种编程语言都有自己的解决方案。在Dart语言中,采用了注解这一高效手段来解决这些问题。
二、什么是注解?
在Dart语言中,注解是一种特殊的语法,用于在编译时或运行时向代码添加额外的元数据。注解以@符号开头,后跟一个编译时常量表达式。这种元数据可以用于指导工具(如静态分析器、编译器和构建器)执行特定操作,例如代码生成、静态检查和优化。注解不会影响程序的执行过程,但可以在编译时或运行时被工具和库访问,以实现各种目的。
用人话来说,就好比购物网站给每个人打上标签,A是大款,B是美女,C是抠脚大汉,然后给你生成首页的时候,找出这些标签去显示不同的商品。
三、 为什么要使用注解开发
注解就像是一把神奇的钥匙,为我们解锁了许多高效开发的大门。以下是使用注解的一些原因:
- 自动生成代码:注解就像会魔法的小精灵,能够在编译时自动生成代码,减轻了我们手动编写重复代码的负担,让开发变得更加轻松。
- 简化代码:注解可以减少重复代码,提高代码质量。
- 提高可读性:注解可以将元数据与实际代码分离,使代码更易于理解。
- 扩展功能:通过注解和注解处理器,我们可以在编译时执行一些额外操作,例如代码检查、代码优化等
以下是一些常见的注解示例:
-
@override:这个注解表示一个方法覆盖了父类的方法。它可以帮助我们检查是否正确地实现了方法覆盖,如果没有正确实现,编译器会给出警告。class Animal { String makeSound() { return "makeSound"; } } class Dog extends Animal { @override void makeSound() { print('makeSound'); } } -
@JsonSerializable():这个注解就是我们项目中使用到的json_annotation库的@JsonSerializable()注解。@JsonSerializable() class ConversationListEntity { String? nextSeq; late List<ConversationListResList> resList; ConversationListEntity(); factory ConversationListEntity.fromJson(Map<String, dynamic> json) => $ConversationListEntityFromJson(json); Map<String, dynamic> toJson() => $ConversationListEntityToJson(this); @override String toString() { return jsonEncode(this); } } -
我们项目中的
@RootView(jumpId: "1005"):用来为订单详情页面生成路由代码。@RootView(jumpId: "1005") class OrderDetail extends BaseWidget { OrderDetail({Key? key}) : super(); @override OrderDetailState createState() => OrderDetailState(); }
四、如何进行注解开发
1、创建 package
想要创建初始的 Flutter package,请使用带有 --template=package 标志的 flutter create 命令:
flutter create --template=package my_router
2、配置依赖
dev_dependencies:
build: ^2.0.0
build_runner: ^2.0.0
source_gen: ^0.9.1
3、开发
-
创建注解类
class InjectMath{ const InjectMath(); }使用
@InjectMath() abstract class MyMath{ add(int a,int b){} } void main() { var sum = MyMathImp().add(1, 2); print("sum:${sum}"); } -
针对注解类创建Generator去解析
MathMethodGenerator
- 收集每个页面的 注解(RootView),并对注解信息进行解析,存到静态变量rootViewInfo中,不要生成文件
// 这个是比较关键的代码 class MathMethodGenerator extends GeneratorForAnnotation<InjectMath> { late String className; @override generateForAnnotatedElement(Element element, ConstantReader annotation, BuildStep buildStep) { final emitter = DartEmitter(); className = element.displayName; ClassBuilder classBuilder; var channelHelper = Class((builder) { classBuilder = builder; // 类名 classBuilder.name = "${className}Imp"; // 对某个类进行实现 classBuilder.implements.add(refer(className)); // 添加方法 classBuilder.methods.add(Method((methodBuild) { methodBuild.name = "add"; methodBuild.annotations.add(TypeReference((build) { // 给方法添加注解 build.symbol = "override"; //注解类型是override })); methodBuild.returns = Reference("int"); methodBuild.requiredParameters.add(Parameter(((parameterBuilder) { parameterBuilder.name = "a"; parameterBuilder.type = Reference("int"); }))); methodBuild.requiredParameters.add(Parameter(((parameterBuilder) { parameterBuilder.name = "b"; parameterBuilder.type = Reference("int"); }))); methodBuild.body = Code("return a + b;"); })); }); String channelHelperStr = DartFormatter().format('${channelHelper.accept(emitter)}'); return """ part of '${Path.basename(buildStep.inputId.path)}'; $channelHelperStr """; } } -
创建Builder去调用Generator
Builder mathMethodBuilder(BuilderOptions options) => LibraryBuilder(MathMethodGenerator(), generatedExtension: '.math.g.dart'); -
配置build.yaml
在
build.yaml文件中,你可以定义生成器、构建器以及它们的相关设置。这些设置包括:- 生成器和构建器的输入和输出文件类型
- 生成器和构建器的自动应用规则
- 目标源文件的匹配模式
- 构建选项,如是否启用缓存、输出目录等
builders: math_builder: import: 'package:my_router/builder.dart' builder_factories: ['mathMethodBuilder'] build_extensions: {'.dart': ['.math.g.dart']} auto_apply: root_package build_to: source
五、使用
通过运行一下命令生成代码
flutter pub run build_runner clean
flutter pub run build_runner build --delete-conflicting-outputs
注意点: build_runner会存在缓存,如果generateForAnnotatedElement返回null,那后面此注解就不会被build了,可以通过一下命令解决。
flutter pub run build_runner clean
六、debug
在注解开发过程中,我们常常会遇到一些调试难题,例如:为什么代码没有生成;如何查看复杂对象的属性;如何进行流程分析等。如果不利用断点调试技术,解决这些问题将变得相当困难。接下来,我将分享在调试过程中积累的一些经验和心得,希望能对大家有所帮助。
- 将
build/entrypoint/build.dart,复制到项目根目录中
- 点击
Edit Configurations进行配置- 添加
Dart Command Line App - 选择Dart file
program arguments中输入serve
- 添加
六、总结
通过本次轻松愉快的注解之旅,相信您已经对 Flutter 中注解的开发有了更深入的了解。注解不仅为我们的代码增添了趣味,还让我们的开发变得更加高效。在实际开发过程中,不妨尝试使用注解,体验它们带来的神奇力量吧!