This is the 15th day of my participation in the August More text Challenge. For details, see: August More Text Challenge

Important note, because the latest version of the Flutter requires an Xcode upgrade, the upgrade system was upgraded to Big Sur (11.5.2) and Xcode was upgraded to 12.4. The Flutter has been upgraded to the latest stable version 2.2.3 (Dart version 2.13.4) and future examples will be based on version 2.2.3 (previous version was 2.0.6). If you want to switch from one version to another, check out The introduction and Practice of Flutter (51) : The Null Safety version of the state Management section of the Flutter switch development has been submitted: The State Management version 2.2 code.

preface

Due to the upgrade of the Flutter version, I ran through the previous code after the upgrade, and it was no problem. The biggest difference is that the updated version now supports the NULL Safety version of Dart. Null Safety is nothing new, Swift has been supporting it for a long time, and Dart has been supporting it since version 2.12.2. This article uses the official documentation as a blueprint to discuss the NULL Safety feature of Dart. Link to official document: Null Safety.

The best feature of NULL Safety is that the object is declared to be non-empty by default, unless you specify that the object can be null.

Nullable and non-Nullable types

When you choose to use the NULL satety feature, all types are non-null by default. For example, if you declare a variable of type String, that means it always contains a String value. If you want a String to accept a String value or null, you need to add? Identity, a declaration of String? Variables of type can contain string values or null.

String? str1;
String str2;
// OK
str1 = null;
/ / an error
str2 = null;
// OKList<String? > strList1 = ['a',null, 'c'];
/ / an error
List<String> strList2 = ['a', null, 'c'];
Copy the code

The empty assertion operator!

If you determine that an object or expression returns a value, you can use the null assertion operator! Then you can use it to assign to a non-empty object, or access properties or methods, like “unavailable!” Xx. In this case, if you do not add! , the compiler will report an error. However, if the object itself is null, add! Operator causes an exception.

int? couldReturnNullButDoesnt() => - 3; void main() { int? nullableInt = 1; List<int? > intListHasNull = [2, null, 4]; int a = nullableInt! ; int b = intListHasNull.first! ; int c = couldReturnNullButDoesnt()! .abs(); print('a is $a.'); print('b is $b.'); print('c is $c.'); }Copy the code

Type promotion

To ensure empty security, Dart’s flow analysis has been designed with empty features in mind. If a Nullable object cannot be null, it is treated as a non-null object. For example:

String? str; if (str ! =null) {
  print(str);  // It has been ensured that it is not empty and will not cause compilation errors
}
Copy the code

The newest keyword

There are times when variables, class member attributes, or other global variables should be non-empty, but cannot be directly assigned to them. In this case, the late keyword should be added to the variable declaration. When the late keyword is added to the variable declaration, Dart is told the following:

  • No value has been assigned to this variable yet;
  • We will not assign a value to this variable until later;
  • We guarantee that we will assign a value to the variable before we use it.

For example, the _description below states that the compiler will report an error if there is no late keyword.

class Meal {
   late String _decription; // Error declaration
  
  set description(String desc) {
    _description = 'Meal Description: $desc';
  }
  
  String get description => _description;
}

void main() {
  final myMeal = Meal();
	myMeal.description = 'Feijoada';
	print(myMeal.description);
}
Copy the code

The late keyword is also very helpful in dealing with circular references. For example, we have a team and a coach, and teams and coaches are mutually applied. Without the late keyword, we’d just have to declare nullable, which would be awkward to use when the time is right — we’d need to add the null assertion operator here and there or use if to determine whether it’s null.

class Team { late final Coach coach; } class Coach { late final Team team; } void main() { final myTeam = Team(); final myCoach = Coach(); myTeam.coach = myCoach; myCoach.team = myTeam; Print (' done! '); }Copy the code

Upgrade to modify

During the upgrade and modification, you need to perform the following operations based on the invoked method parameters, return values, or declared attributes:

  • Class attributes: Non-empty class attributes need to be initialized by default, and can be added if the class attributes are to be initialized in another methodlateKeyword indicating that the property will be initialized later and is non-empty. If the property is likely to be empty, then add?Empty logo. This nullable property needs to be used with special care. It needs to be checked to see if it is null before it can be used or usedvariable? .xxThis formal access is required if the property explicitly has a value. Mandatory non-null, such asvariable! .xx.
  • Method parameter: Set whether the parameter can be null or mandatory as required. Add the mandatory parameter is added before the parameter declarationrequiredKeyword, which can be empty plus?Logo.
  • Return value: if the return value may benull, just after the return parameter?Logo. If an object in a collection object is empty, you need to add? Identification, for exampleList<int? >.

For dependencies, you also need to modify the pubspec.yaml file, including the following changes:

  • Change the lowest-dependent Dart version to 2.12.0
environment:
  sdk: "> = 2.12.0 < 3.0.0"
Copy the code
  • Modified some third-party plug-ins to support null Safety. For details, see the version description on pub.

Dio on pit

DioError [DioerrorType. other]: type ‘Null’ is not a subtype of type ‘Object’. Internet search, in the issue has mentioned, but said it has been solved. Then I tried the method in the issue, but it did not work. After thinking about it, I first directly requested baidu web page to see if there was a problem with Dio. As a result, the baidu web page was normal, which indicated that the problem was the code itself. The request headers of our CookieManager interceptor set the Cookie field, and when _cookie is null, it causes an empty exception. At this point we need to check that the Cookie is not null.

// The code before CookieManager, _cookie may be null causing Dio to report an exception
void onRequest(
  RequestOptions options,
  RequestInterceptorHandler handler,
) {
  options.headers['Cookie'] = _cookie;

  return super.onRequest(options, handler);
}

/ / modified
@override
void onRequest(
  RequestOptions options,
  RequestInterceptorHandler handler,
) {
  // Null safety must not be setif (_cookie ! = null) { options.headers['Cookie'] = _cookie; } return super.onRequest(options, handler); }Copy the code

conclusion

From a coding perspective, the NULL safety feature actually increases the coding effort. But NULL Safety is more of a mandatory convention that requires an interface or class to specify whether a parameter or attribute is null, thus simplifying collaboration and improving code robustness.

Dart does not use a null check for dynamic variables and properties, which can cause a null exception to occur. For example, the headers for RequestOptions options is a Map

object, and null assignment will raise an exception. In this case, it is best to use dynamic declarations as little as possible, and if this happens when you call a third party, you need to check to see if null assignment is allowed.
,>


I’m an island user with the same name on wechat. This is a column on introduction and practice of Flutter.

👍🏻 : feel a harvest please point to encourage!

🌟 : Collect articles, convenient to read back!

💬 : Comment exchange, mutual progress!