Serialisierung zu JSON und einem unveränderlichen Objekt. Informationen zum Paket built_value für Flutter





Manchmal muss JSON von einer API in ein Objekt und vorzugsweise in einen unveränderlichen Wert konvertiert werden. Auf Dart ist es möglich, aber es erfordert viel Codierung für jedes der Objekte. Glücklicherweise gibt es ein Paket, das Ihnen dabei hilft, und in diesem Artikel werde ich Ihnen über diese Methode berichten.



Unser Ziel:



1. Serialisierung



final user = User.fromJson({"name": "Maks"});
final json = user.toJson();


2. Als Werte verwenden



final user1 = User.fromJson({"name": "Maks"});
final user2 = User((b) => b..name='Maks');
if (user1 == user2) print('    ');


3. Unveränderlichkeit



user.name = 'Alex'; // 
final newUser = user.rebuild((b) => b..name='Alex'); // 




Installieren Sie Pakete



Öffnen Sie die pubspec.yaml Datei in unserem Flutter Projekt und fügen Sie das built_value Paket zu Abhängigkeiten :



  ...
  built_value: ^7.1.0


Und auch die Add built_value_generator und build_runner Pakete zu dev_dependencies . Mit diesen Paketen können Sie die erforderlichen Codes generieren.



dev_dependencies :



 ...
  build_runner: ^1.10.2
  built_value_generator: ^7.1.0


Speichern Sie die Datei pubspec.yaml und führen Sie " flutter pub get " aus, um alle erforderlichen Pakete zu erhalten.



Erstellen Sie einen gebauten Wert



Lassen Sie uns eine einfache Klasse erstellen, um zu sehen, wie dies funktioniert.



Erstellen Sie eine neue Datei user.dart :



import 'package:built_value/built_value.dart';

part 'user.g.dart';

abstract class User implements Built<User, UserBuilder> {
  String get name;

  User._();
  factory User([void Function(UserBuilder) updates]) = _$User;
}


So haben wir eine einfache abstrakte Benutzerklasse mit einem Namen Feld , darauf hingewiesen , dass unsere Klasse Teil ist user.g.dart und die Haupt-Implementierung ist es, einschließlich UserBuilder . Um diese Datei automatisch zu erstellen, müssen Sie dies in der Befehlszeile ausführen:



flutter packages pub run build_runner watch


oder



flutter packages pub run build_runner build


Wir beginnen mit der Uhr , um nicht jedes Mal neu zu starten, wenn sich etwas in der Klasse ändert.



Danach sehen wir, dass eine neue Datei user.g.dart angezeigt wurde . Sie können sehen, was sich darin befindet und wie viel Zeit wir durch die Automatisierung dieses Prozesses sparen. Wenn wir mehr Felder und Serialisierung hinzufügen, wird diese Datei noch größer.



Lassen Sie uns überprüfen, was wir haben:



final user = User((b) => b..name = "Max");
print(user);
print(user == User((b) => b..name = "Max")); // true
print(user == User((b) => b..name = "Alex")); // false


nullable



Fügen Sie der Benutzerklasse ein neues Feld für den Nachnamen hinzu :



abstract class User implements Built<User, UserBuilder> {
  String get name;
  String get surname;
...
}


Wenn Sie es so versuchen:



final user = User((b) => b..name = 'Max');


Dann bekommen wir eine Fehlermeldung:



Tried to construct class "User" with null field "surname".


Verwenden Sie, um den Nachnamen optional zu machennullable::



@nullable
String get surname;


oder Sie müssen jedes Mal einen Nachnamen angeben :



final user = User((b) => b
  ..name = 'Max'
  ..surname = 'Madov');
print(user);


Gebaute Sammlung



Verwenden wir Arrays. BuiltList hilft uns dabei :



import 'package:built_collection/built_collection.dart';
...
abstract class User implements Built<User, UserBuilder> {
  ...
  @nullable
  BuiltList<String> get rights;
...


final user = User((b) => b
  ..name = 'Max'
  ..rights.addAll(['read', 'write']));
print(user);


Aufzählung



Es ist notwendig, Rechte einzuschränken, damit keine anderen Werte als " Lesen ", " Schreiben " und " Löschen " verwendet werden. Erstellen Sie dazu eine neue Datei mit dem Namen right.dart. Erstellen Sie eine neue EnumClass :



import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';

part 'right.g.dart';

class Right extends EnumClass {
  static const Right read = _$read;
  static const Right write = _$write;
  static const Right delete = _$delete;

  const Right._(String name) : super(name);

  static BuiltSet<Right> get values => _$rightValues;
  static Right valueOf(String name) => _$rightValueOf(name);
}


Nutzer:



@nullable
BuiltList<Right> get rights;


Jetzt akzeptieren Rechte nur den richtigen Typ :



final user = User((b) => b
  ..name = 'Max'
  ..rights.addAll([Right.read, Right.write]));
print(user);


Serialisierung



Damit diese Objekte problemlos in JSON und zurück konvertiert werden können , müssen wir unseren Klassen einige weitere Methoden hinzufügen:



...
import 'package:built_value/serializer.dart';
import 'serializers.dart';
...
abstract class User implements Built<User, UserBuilder> {
...
  Map<String, dynamic> toJson() => serializers.serializeWith(User.serializer, this);
  static User fromJson(Map<String, dynamic> json) =>
serializers.deserializeWith(User.serializer, json);

  static Serializer<User> get serializer => _$userSerializer;
}


Im Prinzip reicht dies für die Serialisierung aus:



static Serializer<User> get serializer => _$userSerializer;


Fügen wir der Einfachheit halber die Methoden toJson und fromJson hinzu .



Wir fügen der rechten Klasse auch eine Zeile hinzu:



import 'package:built_value/serializer.dart';
,,,
class Right extends EnumClass {
...
  static Serializer<Right> get serializer => _$rightSerializer;
}


Und Sie müssen eine weitere Datei namens serializers.dart erstellen :



import 'package:built_collection/built_collection.dart';
import 'package:built_value/serializer.dart';
import 'package:built_value/standard_json_plugin.dart';
import 'package:built_value_demo/right.dart';
import 'package:built_value_demo/user.dart';

part 'serializers.g.dart';

@SerializersFor([Right, User])
final Serializers serializers =
(_$serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();


Jede neue Gebaute Klasse muss hinzugefügt werden @SerializersFor ([ ... ]) für die Serialisierung zu arbeiten , wie erwartet .



Jetzt können wir überprüfen, was wir haben:



final user = User.fromJson({
  "name": "Max",
  "rights": ["read", "write"]
});
print(user);
print(user.toJson());


final user2 = User((b) => b
  ..name = 'Max'
  ..rights.addAll([Right.read, Right.write]));
print(user == user2); // true


Ändern wir die Werte:



final user3 = user.rebuild((b) => b
  ..surname = "Madov"
  ..rights.replace([Right.read]));
print(user3);


zusätzlich



Infolgedessen wird es diejenigen geben, die sagen, dass Sie noch ziemlich viel schreiben müssen. Wenn Sie jedoch Visual Studio-Code verwenden, empfehle ich , ein Snippet mit dem Namen Built Value Snippets zu installieren, und Sie können dies alles automatisch generieren. Suchen Sie dazu den Marktplatz oder folgen Sie diesem Link .



Nach der Installation schreiben Sie " bv " in die Dart-Datei und Sie können sehen, welche Optionen vorhanden sind.



Wenn Sie nicht möchten , Visual Studio - Code zu den erzeugten „zeigen * .g.dart “ Dateien, müssen Sie öffnen Einstellungen und suchen nach Dateien: Ausschließen und klicken dann auf Add - Muster und fügen Sie ** / *. g.dart ”.



Was weiter?



Auf den ersten Blick mag es so aussehen, als ob sich so viel Aufwand nicht lohnt, aber wenn Sie viele solcher Klassen haben, wird dies den gesamten Prozess erheblich erleichtern und beschleunigen.



PS Ich würde mich sehr freuen und Ihnen danken, wenn Sie Ihre Methoden teilen, die Sie praktischer und effektiver finden als die von mir vorgeschlagene.



GitHub-Projektpakete



:

pub.dev/packages/built_value

pub.dev/packages/built_value_generator

pub.dev/packages/build_runner



All Articles