Fluent -- JSON parsing

Contents of this article

Preface

The previous blog has introduced the network request in the development of Flutter in detail, but in fact, in most projects, it is not enough to return HTML content. Because the most used request of mobile terminal is JSON data, so we need to master the knowledge of JSON parsing in the development of Flutter. (JSON(javaScript Object Notation) is a lightweight data exchange format)

JSON to Dart object

Suppose that we are now developing a news App. After accessing the relevant interface, the server returns such a simple JSON data, as shown in the following figure:

{"title":"The emergence of the epidemic vaccine has brought great benefits to many sectors"}

So how should we deal with this data display on the interface? I believe that readers who have experience in Java Android development will know how to restore this data to an object and display it in the interface. Similarly, in the development of Flutter, you can also convert this JSON data into Dart objects. First, we define Dart object News, and the code is as follows:

class News{
  final String title;
  
  News({this.title});
  
  factory News.fromJson(Map<String,dynamic> json){
    return News(
      title: json['title'],
    );
  }
}

There is a JSON constant in dart:convert, which is responsible for processing the JSON data returned by the server. When the request response comes back, the JSON result can be converted to Map type or List type by calling the json.decode(response.body) method. If it is a JSON object, it will return a Map; if it is a JSON array, it will return a List.

The reason why the above code defines the value of map as dynamic is that it is not sure whether the value type is string, integer or automatic matching type.

practice

After JSON parsing, we need to show the results to the user in the form of an interface, so we can directly implement its functions as follows:

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState(news: httpPost());
}

class _MyHomePageState extends State<MyHomePage> {

  final Future<News> news;
  _MyHomePageState({Key key,this.news});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("HttpClient"),
      ),
      body:Center(
        child: FutureBuilder<News>(
          future: news,
          builder: (context,snapshot){
            if(snapshot.hasData){
              return Text(snapshot.data.title);
            }else if(snapshot.hasError){
              return Text("Wrong.");
            }
            return CircularProgressIndicator();
          },
        ),
      ),
    );
  }
}

Future<News> httpPost() async{
  final response=await http.get("http://liyuanjinglyj.com/demo/");
  if(response.statusCode==200){
    print(utf8.decode(response.bodyBytes));
    return News.fromJson(json.decode(response.body));
  }else{
    throw Exception('No request JSon');
  }

}

class News{
  final String title;

  News({this.title});

  factory News.fromJson(Map<String,dynamic> json){
    return News(
      title: json['title'],
    );
  }
}

The code is very simple. Here, a Dart class of JSON is specifically defined to process JSON data, and JSON is displayed on the screen with the FutureBuilder component. The first picture of the display effect is shown.

Generate entity classes with tools according to JSON

It can be said that JSON format is generated statically, that is to say, a JSON class is defined manually. But if there are many data in JSON format, how to get JSON data? It's very troublesome to write one by one, so we need to use tools to automatically generate JSON classes. Here, we also need to import dependencies in pubspec.yaml:

dependencies:
  json_annotation: ^2.0.0

dev_dependencies:
  build_runner: ^1.0.0
  json_serializable: ^2.0.0

Then we create an entity class in the following format:

import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

@JsonSerializable()
class User{
  String name;
  String email;
  User({this.name,this.email});

  factory User.fromJson(Map<String,dynamic> json)=>_$UserFromJson(json);

  Map<String,dynamic> toJson=>_$UserToJson(this);
}

Error will be reported here, especially part "user.g.dart"; and the last two sentences will show a red wavy line prompt, but this is normal. We can treat the above code as a template, and then we enter the following command under the project directory file:

flutter packages pub run build_runner build

After entering this command, a user.g.dart file will be generated. In the user.dart directory, the code is as follows:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'user.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

User _$UserFromJson(Map<String, dynamic> json) {
  return User(name: json['name'] as String, email: json['email'] as String);
}

Map<String, dynamic> _$UserToJson(User instance) =>
    <String, dynamic>{'name': instance.name, 'email': instance.email};

In order to be intuitive, bloggers have reduced many parameters, but in reality, JSON parameters will certainly have many, even hierarchy. In this case, it will be more convenient and time-saving to generate automatically.

But there is also a flaw in this way, that is, if my JSON format is changed, it can't be generated once? Obviously, considering this situation, Flutter provides us with a listening mode to realize every generation. The commands are as follows:

flutter packages pub run build_runner watch

This command only needs to be executed once, so it will be monitored and run in the background all the time, and it can be generated automatically without our operation.

When the JSON class property is inconsistent with the server return property

Although the above operation is very convenient, there is still a problem to be solved in automatic generation. What should I do when my JSON class is inconsistent with the field returned by the server? Of course, you can change the fields directly, but you may need to change all the contents as soon as you change them, so it is more efficient to use JsonKey annotation at this time, for example:

@JsonKey(name:'user_name')
final String userName;

In this way, annotation and automatic generation of JSON classes are perfect and efficient, which can greatly improve the development efficiency of the program.

Published 109 original articles, praised 141, visited 1 million+
His message board follow

Keywords: JSON snapshot network Mobile

Added by dnszero on Mon, 10 Feb 2020 12:16:29 +0200