一文处理Flutter NullSafety工程兼容问题

1. 布景

Dart语言在2.12以上开端完成NullSafety空安全功用,因而在Flutter工程敞开Null Safety需指定Dart版别>=2.12.0 , 当然指定<2.12以下能够封闭NullSafety;

environment:
  sdk: ">=2.12.0 <3.0.0"

搬迁NullSafety有什么优势呢?

  • Dart/Flutter社区绝大多数pub库现已都搬迁至NullSafery,敞开空安全属于一种趋势;

  • 更简约代码进行判空逻辑处理,完成更优质代码,比方如下代码会直接提示过错,因为controller或许为null,这确保在运用时防止出现null状况;

 ScrollController controller;
 controller.position;
  • 体系针对非空目标进行编译优化,具有更快的运转速度;

搬迁进程会遇到的问题:

  • 空安全敞开后主库房/插件等搬迁的兼容性问题;
  • 空安全敞开后单测才能完成的兼容性问题;

2. Null Safety 高雅代码

  • 编译期提示报错

      String name;
      print('name is $name.');
    

    敞开空安全后上述代码无法编译经过,在非空安全代码下这段代码是可正常编译经过的,提高代码健壮性;

  • ! 操作符

    String? name;
    void main() {
      setName();
      if (name!.isNotEmpty) {
        print('name = ${name.toString()}');
      }
    }
    void setName() {
      name = 'marry';
    }
    

    确认目标运用时非空,能够在表达式添加!,确保后续都不需要写判空条件;

  • late 延迟确认某个目标不为空

    class _ListWidgetState extends State<ListWidget> {
      late ScrollController controller;
      @override
      void initState() {
        controller = ScrollController();
        super.initState();
      }
      @override
      Widget build(BuildContext context) {
        return ListView(
          controller: controller,
          children: [],
        );
      }
    }
    

    如上,开端controller时一个空的目标,但是当运用它时必须确保非空,此刻能够运用late关键字表明目标在时分时必须为非空目标,防止写判空条件;

  • 集合条件判空条件

    在非空安全dart版别,List/Set/Map中集合或许存在null元素,需要在遍历进程剔除后运用,但是晋级空安全版别后,能够List运用元素无法在刺进空元素;假如想在List集合刺进空元素需运用List<String?>,比照List? list则表明list集合或许时空;

3. 工程兼容问题处理

3.1 lib模块搬迁空安全遇到的兼容性问题大致会分为如下几类:

  • 主库房敞开空安全,而插件未兼容空安全运转
Error: Cannot run with sound null safety, because the following dependencies
don't support null safety:
 - package:intl

遇到这种状况能够运用flutter run –no-sound-null-safety方法执行代码即可

  • 主库房未敞开空安全,拆分module模块或插件先支持了空安全:这种模式运转应该是没有任何问题的,空安全可向下兼容非空安全代码;

  • 代码库房过大,想敞开空安全代码,但是不想动旧代码,只想将特性应用在新代码上:

    这个应该是实际开发遇到的最多场景,遇到较大工程模块时,许多开发没有精力做搬迁工作,那可不能够敞开空安全后混编模式运转呢?经测试发现,只需要将没有完成空安全的文件开头添加@dart = xxx如下代码即可:

    // @dart = 2.9
    import 'package:flutter/material.dart';
    class ListDemo extends StatefulWidget {
      const ListDemo({Key key}) : super(key: key);
      @override
      State<ListDemo> createState() => _ListDemoState();
    }
    

    如上,我指定dart版别号为2.9运转环境,当dart<2.12时空安全相关功用即失效,这样就能够完成混合空安全和非空安全模式开发;因而完成一个python脚本将旧模块代码一次性添加dart版别注释就能够暂时敞开空安全;

3.2 单测模块搬迁问题大致分为如下几种

  • 敞开空安全后的单测代码会遇到如下问题:

    Error: Cannot run with sound null safety, because the following dependencies
    don't support null safety:
     - package:intl
    

    这里碰到插件依靠非空安全库执行问题不能和上面库房代码搬迁相似执行flutter run –no-sound-null-safety绕过,主要原因是因为flutter test不支持–no-sound-null-safety指令执行,因而只能在单测模块指定@dart = xxxx版别号,将空安全功用封闭,目前暂未发现其他处理方案;

  • 敞开安全后或许会遇到dart版别号注释指定抵触问题:

    57aa4681533c35fd526e75c0f98d7db906ceefaa/lib/src/messages.dart:4:1: Error: A library can't opt out of null safety by default, when using sound null safety.
    // @dart = 2.8
    ^^^^^^^^^^^^^^
    

    这个主要是多个版别dart注释版别抵触引起,你只需要将test环境下的dart版别略微比抵触的版别大于等于即可;

4. 总结

空安满是一个好东西,能够减少许多非必要的判空条件,确保代码健壮性,一起提高代码可读性,使得代码更加高雅;本文主要介绍空安全优势一起在搬迁空安全进程发现的一个问题,记载描述空安全搬迁进程中一些需要兼容的问题,希望对大家有所帮助;