看到有同窗想要代碼,這個在原文中都有。我也正在開發一個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
裏就能夠,很酷對吧。
運行代碼,你會看到這樣的界面: