Flutter:解析JSON
2020/4/17 5:06:33
本文主要是介绍Flutter:解析JSON,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
看到有同学想要代码,这个在原文中都有。我也正在开发一个app,代码比原文里的还要接近实际使用。
准备
如果可以的话还是请看原文。我这都按照我的理解翻译的,仅供参考。
如果一个App界面上什么都没有的话,那么绝对够无聊的。但是你的app从哪里可以获得有趣的内容呢?必须是网络了。你的,你公司的后端或者是网络上的公开API!
很多的网站提供了REST API,一般只要注册就可以使用他们的API。在本文中会用到一个瞄星人的站点,你会在那里注册。并把数据展示在一个Flutter app里。在这个站点的API里你会获得一个喵星人的列表,每个item里面还有一些数据以及喵星人的图片。
JSON:是JavaScript Object Notation的缩写,基本上所有的API都在用这个数据格式。在本文中你会学到如何把JSON串解析成一个model类的对象,如何把它显示在屏幕上。详细内容包括:
- 调用网络API
- 解析JSON数据
- 把数据显示在一个
ListView
里。 - 显示网络图片
开始
本教程的代码在这里,点击下载材料获取。
本文会使用Android Studio和Flutter插件来开发。你也可以使用Visual Studio Code,IntelliJ IDEA来开发。要给Android Studio装Flutter插件,找到Plugins:
点击“市场”,找到Flutter,之后点击安装按钮。安装了这个plugin之后也就安装了dart plugin了。如果没有自动安装的话,手动安装一下。
这些plugin都装好之后,重启android studio。在开始界面上选择打开一个已经存在的Android Studio项目然后找到下载好的代码的根目录:
Android Studio会弹出一个框获取项目路里用到的包。继续,之后你会看到:
所有的准备工作完成之后,在设备下拉表里选择一个iOS模拟器或者android模拟器,当然如果你用的是mac,而且Xcode也安装了的话。点击运行按钮。
开始项目就会运行起来,在iOS模拟器是这样的:
Android模拟器是这样的:
理解UI
现在屏幕上还没有任何的数据。接下来就要把数据加上去。
breed, 这里是指猫的品种。
打开lib/screens/cat_breeds.dart文件你会看到如下的代码:
import 'package:flutter/material.dart'; import 'cat_info.dart'; class CatBreedsPage extends StatefulWidget { // 1 CatBreedsPage({Key key, this.title}) : super(key: key); final String title; @override _CatBreedsPageState createState() => _CatBreedsPageState(); } class _CatBreedsPageState extends State<CatBreedsPage> { @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( // 2 title: Text(widget.title), ), // 3 body: ListView.builder( // 4 itemCount: 0, itemBuilder: (context, index) { // 5 return GestureDetector( onTap: () { Navigator.push(context, MaterialPageRoute(builder: (context) { return CatInfo(catId: 'id', catBreed: 'Name'); })); }, // 6 child: Card( child: Padding( padding: const EdgeInsets.all(8.0), // 7 child: ListTile( title: Text('Breed Name'), subtitle: Text('Breed Description'), ), ), ), ); }), ); } }
解释:
- 构建一个
CatBreedsPage
- 在
AppBar
里设置title
字段的值 - 把
ListView.builder
作为字段的方法 -
count
设置为0,毕竟现在还没有任何的数据 - 使用
Navigator
类跳转到CatInfo
详情页 - 创建一个
Card
,里面放一个Padding
- 添加一个包含title和descriptin的
ListTile
。
使用REST API
请求REST API的时候有不同的method,一般是GET:用来获取数据,也有POST来保存数据,PATCH和PUT用来更新数据。另外还有个DELETE method,用来删除数据。
如果你看过喵星人API,你就会你可以使用的请求method。如果你点开Search by Breed连接,你会发现需要一个API key才能用这些API。
注册Cats API
跳转到这里注册一个账号。这一步是必须的,否则的话那些API都没法调用。
调用网络API
请求API在dart来说是一件很轻松的事。你只需要使用开始项目里的HTTP库。打开lib/api/network.dart文件,代码是这样的:
// 1 import 'package:http/http.dart'; class Network { final String url; //2 Network(this.url); // 3 Future getData() async { print('Calling uri: $url'); // 4 Response response = await get(url); // 5 if (response.statusCode == 200) { // 6 return response.body; } else { print(response.statusCode); } } }
解释如下:
- 引入HTTP库
-
Network
类有一个接受一个字符串为参数的构造函数 - 包含了一个异步方法
getData()
- 使用HTTP GET method请求url,并等待返回
- 检查状态码,如果是200那么返回是OK的,否则就是一个Error
- 返回结果
理解JSON
JSON大多数REST API返回的数据的格式。另外一个通用格式是XML。
JSON实例:
{ "user": { "name": "Kevin Moore", "occupation": "Programmer" } }
上面的例子是从一个{大括号开始,说明是一个对象数据。JSON也可以是一个数组,这时候一般是[开头。JSON格式不能出错,也就是又开始就需要有结束,当它是一个对象的时候就需要有结束的大括号}。
在服务端返回了一个JSON串之后,你可以:
- 从字符串里获得key/value对
- 把字符串转化为一个dart的
Map
对象,再从里面拿到key/value对。 - 把字符串转化为一个model类的对象,然后从这个对象的属性里获得数据
以上方法都可以获取到数据。但是最好的方法还是把JSON串转化为model类的对象。
解析JSON
我们来看看有哪些方法可以用来解析JSON。
手动解析
你可以使用dart:convert
库来解析:
import 'dart:convert'; Map<String, dynamic> user = jsonDecode(jsonString); var name = user['user]['name'];
这看起来没什么难的。但是如果处理复杂的JSON,代码就会变的冗长繁复。
使用库
在pub.dev,可以找到处理JSON的Flutter库:
- HTTP用来处理网络请求。
- json_annotation用来给你的model类添加注解
你会发现两个工具库可以创建把json串转化为model对象的工具方法:
- build_runner,运行json_serializable库
- json_serializable,创建额外的把json串转化为model对象的工具代码
这俩个库要放在pubspec.yaml文件的dev_dependencies后面。
最后,在pubspec.yaml文件的dependencies
里:
dependencies: flutter: sdk: flutter cupertino_icons: ^0.1.2 http: ^0.12.0+2 json_annotation: ^2.0.0
在dev_dependencies
里:
dev_dependencies: flutter_test: sdk: flutter build_runner: ^1.0.0 json_serializable: ^2.0.0
接下来点击在android studio的右上角出现的Packages get。我们需要的包就回下载下来了。
Cat API
打开lib/api/cats_api.dart文件。第一行就是叫做apiKey
的字符串常量。用你自己的key放进去。
const String apiKey = 'Your Key'; //1 const String catAPIURL = 'https://api.thecatapi.com/v1/breeds?'; // 2 const String catImageAPIURL = 'https://api.thecatapi.com/v1/images/search?'; // 3 const String breedString = 'breed_id='; // 4 const String apiKeyString = 'x-api-key=$apiKey'; class CatAPI { // 5 Future<dynamic> getCatBreeds() async { // 6 Network network = Network('$catAPIURL$apiKeyString'); // 7 var catData = await network.getData(); return catData; } // 8 Future<dynamic> getCatBreed(String breedName) async { Network network = Network('$catImageAPIURL$breedString$breedName&$apiKeyString'); var catData = await network.getData(); return catData; } }
解释如下:
- API的url字符串,获取喵星人列表
- 同样是url串,查找喵星人的图
- 获取一个breed ID
- 存放你的key的字符串
- 获取列表的方法
getCatBreeds()
-
Network
类,需要传入API的url和你的key组成的字符串 - 获取某个breed的喵的图片的方法
getCatBreed(String breedName)
使用Cat API
在文件lib/screens/cat_breeds.dart文件中的_CatBreedsPageState
,里添加如下代码:
void getCatData() async { var result = await CatAPI().getCatBreeds(); print(result); }
这个方法会获得喵的breeds。
这里需要从cat_info.dart文件引入CatAPI
类。你可以手动实现,也可以把光标移到CatAPI
上,然后使用快捷键Option+Enter,选择Import。
接下来在initState()
方法下面添加这个方法:
getCatData();
现在可以运行代码了,你应该可以发现请求API得到的JSON串了:
创建Model类
在Models目录下打开cats.dart文件。你会发现注释掉的JSON串。
添加一个描述喵种的类
class Breed { String id; String name; String description; String temperament; Breed({this.id, this.name, this.description, this.temperament}); }
这个类的字段基本上和从API里获得的数据的字段一致。id
用来获取喵种的图片,name
和description
用来在列表的CardView中显示。
喵种的列表数据就是从[开始,到]结束的一个JSON数组。
class BreedList { List<Breed> breeds; BreedList({this.breeds}); }
这个类里面包含了breeds
列表。
要查找喵种的图片,还需要cat的model类,cat breed的model类以及cat breed列表的model类。添加下面的代码到cats.dart文件里:
class Cat { String name; String description; String life_span; Cat({this.name, this.description, this.life_span}); } class CatBreed { String id; String url; int width; int height; List<Cat> breeds; CatBreed({this.id, this.url, this.width, this.height, this.breeds}); } class CatList { List<CatBreed> breeds; CatList({this.breeds}); }
在教程的app里是不需要用到temperament
和life_span
字段的,当然你可以用这两个字段丰富app的功能。
使用JSON注解
现在可以使用json_annotation库来把数据解析到model类的对象里。
在cats.dart文件里添加如下代码:
import 'package:json_annotation/json_annotation.dart'; part 'cats.g.dart';
part
语句允许你引入一个文件,并使用里面的私有变量。现在会显示一个错误。但是用build_runner文件cats.g.dart之后就不会了。
现在给每个model类添加注解:@JsonSerializable()
。如:
@JsonSerializable() class Breed { String id; String name; String description; String temperament; Breed({this.id, this.name, this.description, this.temperament}); }
JSON转换方法
在这一节,我们会给每个类都加上一个工厂方法。build runner会根据这些方法生成专门处理数据转化的代码。
在Breed
类的构造函数后面添加如下代码:
factory Breed.fromJson(Map<String, dynamic> json) => _$BreedFromJson(json); Map<String, dynamic> toJson() => _$BreedToJson(this);
每个类都会包含一个fromJson
和一个toJson()
方法,这两个方法会调用生成的数据转换方法。现在Android Stuido里会显示一些错误,暂时忽略。
在BreedList
类的构造函数后面添加如下代码:
factory BreedList.fromJson(List<dynamic> json) { return BreedList( breeds: json .map((e) => Breed.fromJson(e as Map<String, dynamic>)) .toList()); }
在Cat
类里添加fromJson
和toJson
两个方法:
factory Cat.fromJson(Map<String, dynamic> json) => _$CatFromJson(json); Map<String, dynamic> toJson() => _$CatToJson(this);
最后在CatList
类的构造函数后面添加如下代码:
factory CatList.fromJson(List<dynamic> json) { return CatList( breeds: json .map((e) => CatBreed.fromJson(e as Map<String, dynamic>)) .toList()); }
使用Build Runner
在项目的终端里运行如下的命令:
flutter packages pub run build_runner build
如果没什么问题就会生出出来我们前文反复提到的cats.g.dart文件。
使用Model类
现在Nodel类都已经完备了,可以用起来了。
开始前,现在_CatBreedsPageState
里添加一个属性:
class _CatBreedsPageState extends State<CatBreedsPage> { BreedList breedList = BreedList(); //<-添加这个属性 ...
引入
引入cats.dart文件。添加dart:convert
。
在getCatData()
方法里,在print语句后面添加如下的代码:
// 1 var catMap = json.decode(result); // 2 setState(() { // 3 breedList = BreedList.fromJson(catMap); });
解释如下:
- 使用
json.decode(result)
从JSON串得到一个map - 调用
setState
来重绘Widget,因为数据已经发生了变化 - 使用
fromJson(catMap)
把得到的map转化为一个喵种的列表
接下来就该把数据显示在界面里了。
跳转到body: ListView.builder
语句,把itemCount:0
替换为:
itemCount: (breedList == null || breedList.breeds == null || breedList.breeds.length == 0) ? 0 : breedList.breeds.length,
这样就会把itemCount
设置为实际数量的item值。
把ListTile
里的title
、subTitle
替换为如下的代码:
title: Text(breedList.breeds[index].name), subtitle: Text(breedList.breeds[index].description),
现在运行代码,会出现如下的界面了:
祝贺你!!!
创建详情页
下一步添加onTap
,在用户点击了一行的时候可以跳转到详情页,并且显示出这个喵种的图片。使用下面的代码替换onTap
里的代码:
return CatInfo(catId: breedList.breeds[index].id, catBreed: breedList.breeds[index].name);
这样就把点击那行的id
和name
都传到了CatInfo
的构造函数里。
现在打开lib/screens/cat_info.dart文件在_CatInfoState
类的initState
上面添加下面的代码:
CatList catList = CatList(); void getCatData() async { var catJson = await CatAPI().getCatBreed(widget.catId); print(catJson); var catMap = json.decode(catJson); print(catMap); setState(() { catList = CatList.fromJson(catMap); }); }
在initState
方法里添加对getCatData()
的调用。
@override void initState() { super.initState(); getCatData(); }
确保import了所有需要的文件。
在getCat()
方法里, 在mediaSize
属性声明的后面添加如下代码:
if (catList == null || catList.breeds == null || catList.breeds.length == 0) { return Container(); }
这会返回一个空的Container
,如果API请求返回的数据为空的话。在height
参数后面添加如下的代码:
// 1 decoration: BoxDecoration(image: DecorationImage( // 2 image: NetworkImage(catList.breeds[0].url),fit: BoxFit.contain, )),
解释如下:
- BoxDecoration,让你可以在Box里画一张图
- NetworkImage,可以通过url加载一张图片
注意,你是要用一个装饰器来显示一张图片,你什么都不用做。只要把url放进NetworkImage
里就可以,很酷对吧。
运行代码,你会看到这样的界面:
这篇关于Flutter:解析JSON的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23实现OSS直传,前端怎么实现?-icode9专业技术文章分享
- 2024-11-22在 HTML 中怎么实现当鼠标光标悬停在按钮上时显示提示文案?-icode9专业技术文章分享
- 2024-11-22html 自带属性有哪些?-icode9专业技术文章分享
- 2024-11-21Sass教程:新手入门及初级技巧
- 2024-11-21Sass学习:初学者必备的简单教程
- 2024-11-21Elmentplus入门:新手必看指南
- 2024-11-21Sass入门:初学者的简单教程
- 2024-11-21前端页面设计教程:新手入门指南
- 2024-11-21Elmentplus教程:初学者必备指南
- 2024-11-21SASS教程:从入门到实践的简单指南