看到有同窗想要代码,这个在原文中都有。我也正在开发一个app,代码比原文里的还要接近实际使用。android
若是能够的话仍是请看原文。我这都按照个人理解翻译的,仅供参考。json
若是一个App界面上什么都没有的话,那么绝对够无聊的。可是你的app从哪里能够得到有趣的内容呢?必须是网络了。你的,你公司的后端或者是网络上的公开API!后端
不少的网站提供了REST API,通常只要注册就可使用他们的API。在本文中会用到一个瞄星人的站点,你会在那里注册。并把数据展现在一个Flutter app里。在这个站点的API里你会得到一个喵星人的列表,每一个item里面还有一些数据以及喵星人的图片。api
JSON:是JavaScript Object Notation的缩写,基本上全部的API都在用这个数据格式。在本文中你会学到如何把JSON串解析成一个model类的对象,如何把它显示在屏幕上。详细内容包括:数组
ListView
里。本教程的代码在这里,点击下载材料获取。bash
本文会使用Android Studio和Flutter插件来开发。你也可使用Visual Studio Code,IntelliJ IDEA来开发。要给Android Studio装Flutter插件,找到Plugins:网络
点击“市场”,找到Flutter,以后点击安装按钮。安装了这个plugin以后也就安装了dart plugin了。若是没有自动安装的话,手动安装一下。app
这些plugin都装好以后,重启android studio。在开始界面上选择打开一个已经存在的Android Studio项目而后找到下载好的代码的根目录:异步
Android Studio会弹出一个框获取项目路里用到的包。继续,以后你会看到:async
全部的准备工做完成以后,在设备下拉表里选择一个iOS模拟器或者android模拟器,固然若是你用的是mac,并且Xcode也安装了的话。点击运行按钮。
开始项目就会运行起来,在iOS模拟器是这样的:
Android模拟器是这样的:
如今屏幕上尚未任何的数据。接下来就要把数据加上去。
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
ListTile
。请求REST API的时候有不一样的method,通常是GET:用来获取数据,也有POST来保存数据,PATCH和PUT用来更新数据。另外还有个DELETE method,用来删除数据。
若是你看过喵星人API,你就会你可使用的请求method。若是你点开Search by Breed链接,你会发现须要一个API key才能用这些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); } } }
解释以下:
Network
类有一个接受一个字符串为参数的构造函数getData()
JSON大多数REST API返回的数据的格式。另一个通用格式是XML。
JSON实例:
{ "user": { "name": "Kevin Moore", "occupation": "Programmer" } }
上面的例子是从一个{大括号开始,说明是一个对象数据。JSON也能够是一个数组,这时候通常是[开头。JSON格式不能出错,也就是又开始就须要有结束,当它是一个对象的时候就须要有结束的大括号}。
在服务端返回了一个JSON串以后,你能够:
Map
对象,再从里面拿到key/value对。以上方法均可以获取到数据。可是最好的方法仍是把JSON串转化为model类的对象。
咱们来看看有哪些方法能够用来解析JSON。
你可使用dart:convert
库来解析:
import 'dart:convert'; Map<String, dynamic> user = jsonDecode(jsonString); var name = user['user]['name'];
这看起来没什么难的。可是若是处理复杂的JSON,代码就会变的冗长繁复。
在pub.dev,能够找处处理JSON的Flutter库:
你会发现两个工具库能够建立把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。咱们须要的包就回下载下来了。
打开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; } }
解释以下:
getCatBreeds()
Network
类,须要传入API的url和你的key组成的字符串getCatBreed(String breedName)
在文件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串了:
在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_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}); }
在这一节,咱们会给每一个类都加上一个工厂方法。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()); }
在项目的终端里运行以下的命令:
flutter packages pub run build_runner build
若是没什么问题就会生出出来咱们前文反复提到的cats.g.dart文件。
如今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串获得一个mapsetState
来重绘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, )),
解释以下:
注意,你是要用一个装饰器来显示一张图片,你什么都不用作。只要把url放进NetworkImage
里就能够,很酷对吧。
运行代码,你会看到这样的界面: