Since the release of Flutter, more and more people have tried to use Dart to perform some functions;

Dart’s past life and present life will not be discussed here. Just know that Flutter is a cross-platform solution from Google, at least without worrying about Dart performance and ecology (if Google really wants to support it).

Take a look at the final display:

The Dart language

According to the latest language rankings… Sorry, Dart is not found. As far as I am concerned, JS has not been put in the front end. It seems that Flutter is currently supported in other fields, but I believe that the situation will be better and better as Flutter prevails.

The Dart language has two modes :JIT and AOT; This is similar to the previous Android/Java situation, where the JVM interpreted execution until ART came along and Android AOT mode started.

JIT is convenient because it does not need to compile in advance and AOT is faster to run, while Flutter applies different modes of debug and release to ensure efficient development and smooth application.

Without getting to the point, let’s take a look at one of Dart’s more unusual features: generics

Dart generics versus other generics

Let’s start with a paragraph about genericsDartCode (permutations and combinations:) :

  List<int> a = <int> [];List<num> b = <num> [];List<dynamic> c = <dynamic> [];List<Object> d = <Object> [];List e = [];

  print(a.runtimeType == b.runtimeType);  // false
  print(a.runtimeType == c.runtimeType);  // false
  print(a.runtimeType == d.runtimeType);  // false
  print(a.runtimeType == e.runtimeType);  // false
  print(b.runtimeType == c.runtimeType);  // false
  print(b.runtimeType == d.runtimeType);  // false
  print(b.runtimeType == e.runtimeType);  // false
  print(c.runtimeType == d.runtimeType);  // false
  print(c.runtimeType == e.runtimeType);  // true
  print(d.runtimeType == e.runtimeType);  // false
Copy the code

RuntimeType = runtimeType; runtimeType = runtimeType;

The generic runtime still exists in Dart.

Generics in Java, by contrast, are arbitrary:

List<Integer> a = new ArrayList<>();
List<Object> b = new ArrayList<>();
List c = new ArrayList<>();
Copy the code

Java generics are erased at runtime, so a, B, and c above are all of List type.

Going back to the Dart section, you can see that only variables C and E have the same runtime type, and if you use a compiler, you can see that:

List c = <dynamic> [];Copy the code

List

is just a List, they’re the same thing.

Given dart’s generic nature, you can’t help but wonder: What is the relationship between List

and List, or List

? And List?

Following the original dart example, we add a few lines of judgment (the variable b is of type List

)

  print(b is List<int>);  // false
  print(b is List<num>);  // true
  print(b is List<Comparable>);  // true
  print(b is List);  // true
Copy the code

Comparable is an abstract class implemented by the num class.

Dart generic List, the List whose generic is the parent of the List whose generic is the subclass of List

This is a little convoluted, just get the idea; In fact, if you have experience in Java development, you will see that this is actually very similar to arrays in Java, see arrays and List collections and type coercion in Java

This illustration illustrates that arrays in Java have inheritance relationships that are similar to real class inheritance relationships.


Next, let’s look at the relationship of generics within generic classes;

void main() {
  var aa = AA.name("123");
  aa.test();
}

class AA<T> {
  T field;

  AA.name(this.field);

  void test() {
    print("".runtimeType); //String
    print(T); //String
    print(field.runtimeType == T);  //true}}Copy the code

This code and the result are not in doubt. The generic is still a String when passed to class AA, but this code is different:

void main() {
  var aa = AA.name([]);
  aa.test();
}

class AA<T> {
  T field;

  AA.name(this.field);

  void test() {
    print([].runtimeType); //List<dynamic>
    print(T); //List<dynamic>
    print(field.runtimeType == T);  //false}}Copy the code

When we create the class, we specify the generic Type List(or List

), and then check AA to see that the runtime types of the generic T and field are different. Although toString is the same, if we print hashCode, we can see that there are two different types.

If we pass in a map type, the result is even less satisfactory

void main() {
  var aa = AA.name({"ss":1});
  aa.test();
}

class AA<T> {
  T field;

  AA.name(this.field);

  void test() {
    print(field.runtimeType); // _InternalLinkedHashMap<String, int>
    print(T); // Map<String, int>
    print(field.runtimeType == T); // false}}Copy the code

The actual type is an implementation class of the generic;

What if you pass in a custom generic class?

void main() {
  var aa = AA.name(BB<num> ()); aa.test(); }class AA<T> {
  T field;

  AA.name(this.field);

  void test() {
    print(field.runtimeType); // BB<num>
    print(T); // BB
      
    print(field.runtimeType == T); // true}}class BB<T> {}
Copy the code

Fortunately, when you customize a generic class, the runtime runtimeType is the same as the generic Type

So much for the discussion of DART generics, here’s a summary:

  1. Generics inRuntime retention
  2. There are relationships between List generics that can be passedisTo judge, asfield is List<num>
  3. List generic even thoughtoStringMethod returns the same value, possibly bothDifferent Type

With that said, let’s get down to business

dart-bean

Beans are just a common description of a class class to indicate a data model.

Again, let’s take a look at beans in other languages;

Let’s start with the usual Java approach:

public class TestBean {
    private String username;
    private boolean isVip;

    public String getUsername(a) {
        return username;
    }

    public TestBean setUsername(String username) {
        this.username = username;
        return this;
    }

    public boolean isVip(a) {
        return isVip;
    }

    public TestBean setVip(boolean vip) {
        isVip = vip;
        return this; }}Copy the code

The kotlin representation is much simpler:

data class TestBean(
        var username: String? = null.var isVip: Boolean = false
)
Copy the code

In fact, the bean code withdrawal is not the key, the important place is how to easily assign to the bean and manipulate the bean, because the JVM language can be reflected, so when we get the json format data from the background, we can easily complete the automatic assignment through some libraries:

var bean = Gson().fromJson("{\"username\":\"www\",\"isVip\":false}",TestBean::class.java)
Copy the code

In DART, beans are coded in much the same way as in other languages, declaring member variables in separate classes:

class TestBean {
  String username;
  bool isVip;
}
Copy the code

If it’s a pure DART project, we can still assign values to beans via mirroring:

import 'dart:mirrors';

class TestBean {
  String username;
  bool isVip;
}

void main() {
  Map<String.dynamic> json = {
    "username": "www"."isVip": false};var class_bean = reflectClass(TestBean);
  var obj = class_bean.newInstance(Symbol.empty, []).reflectee;
  var instance_bean = reflect(obj);
  class_bean.declarations.forEach((key, value) {
    if (value is VariableMirror) {
      var key_string = RegExp("^Symbol\\(\"(.+?) \ \ \ \ ") $")
          .firstMatch(key.toString())
          .group(1); instance_bean.setField(key, json[key_string]); }});print("${obj.username}  ${obj.isVip}"); // www false
}
Copy the code

Dart’s mirror function is a bit of a pain in the ass, but it does work.

Unfortunately, DART does not allow the mirror function to be used with Flutter.

Many people may ask if Flutter has a Json serialization library like Gson/Jackson in Java development. The answer is no! Because such libraries require the use of runtime reflection, this is disabled in Flutter. Run-time reflection interferes with Dart’s Tree shaking, and with Tree shaking, unused code can be “stripped” in the release, which can significantly optimize the size of your application. Since reflection is applied to all code by default, tree shaking is difficult to work because it is difficult to know which code is not used when reflection is enabled, and therefore redundant code is difficult to peel off. Dart reflection is disabled in Flutter, and thus dynamic transformation of Model is not possible.

Therefore, if you want to implement beans in Flutter, you need some other tricks.

flutter dart-bean

In most cases today, you add a named constructor to the bean class, and then a tool automatically generates a portion of the code to help parse and build the bean.

For example, the bean class above generates the following code:

class Response {
  String username;
  bool isVip;

  Response.fromJsonMap(Map<String.dynamic> map)
      : username = map["username"],
        isVip = map["isVip"];

  Map<String.dynamic> toJson() {
    final Map<String.dynamic> data = new Map<String.dynamic> (); data['username'] = username;
    data['isVip'] = isVip;
    returndata; }}Copy the code

Add two more parts:

  1. Named constructors:Response.fromJsonMap, the parameters forMap<String, dynamic>Type used forGenerate beans from JSON; Deserialize json
  2. toJsonMethod to serialize an object to a JSON string

You can convert json strings and beans to each other by adding two methods. However, if you have to write it by hand every time, it can be very troublesome because there may be too many fields required, which is usually done with a tool.

There is also an official library available: JSON_serializable, but if we’re used to the quickness of GsonFormat, we might not be happy with this approach, and dart is currently available There are a number of issues you have to consider when generating beans, such as generics, nested inner classes, etc. In these cases, you can’t generate beans directly through a normal command line or tool.

Here I have rewritten the Java type part to dart and changed the generation method:

The plugin address is jetBrains – plugins-jsonTodartbean;

The Package address is json_holder_impl;

Github: JSON-to-Dart-bean;

It looks something like this:

It is easy to use, just follow the tutorial to import the package, and then install the plug-in. Here are some instructions:

1. Plug-in function

Because the plug-in is modified from GsonFormat, so the naming specification and other previous definitions are used, the main functions include:

  1. In the Dart file, use the shortcut Alt + D to generate the bean from the pasted JSON

  2. Json allows you to change the type at creation time, as GsonFormat does

  3. Json supports nested inner classes. If the inner class does not want to create a new one and wants to use an existing class, you can change the type at creation time to do so:

    • Suppose the default type to generate looks like this:

    • We can change the type or uncheck it to look like this:

  4. Supports continuous nesting of two levels of List, as in this case, generating variables of type List<List> :

    {
        "values":[
            [
            1.2.4]]}Copy the code

2. He points

The plugin simply generates short code to view:

/ / * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//**************************** Generate By JsonToDartBean **********
//**************************** Thu Jun 06 18:33:38 CST 2019 **********
/ / * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

import 'package:json_holder_impl/json_holder_impl.dart';

class FirstBean with JsonHolderImpl<FirstBean> {
  /// [key : value] => [name : www]
  String get name => getValue("name");
  set name(String value) => setValue("name", value);

  FirstBean.fromJson([Map<String.dynamic> json]) {
    fromJson(json);
  }

  @override
  JsonHolderImpl<FirstBean> provideCreator(Map<String.dynamic> json) {
    return FirstBean.fromJson(json);
  }

  @override
  List<FirstBean> provideListCreator() {
    return <FirstBean>[];
  }

  @override
  List<List<FirstBean>> provideListListCreator() {
    return <List<FirstBean>>[]; }}Copy the code

You can see that no member fields are actually generated in the class, and all variables are equally get and Set method, method of building this way relative to the current common bean has a benefit, it is a variable’s value only when it is in real call to parse, can to a certain extent, to speed up the speed (the same processing the type conversion in the parent class, and can be customized, custom methods refer to the above mentioned lot tutorial).

The toJson method is defined in the parent class JsonHolderImpl and can be called directly.

Note: code is not for commercial use note: if there are any copyright issues related to the plugin GsonFormat, please inform us