本篇文章记录我在使用Flutter开发中如何请求后端接口获取数据, 使用到的包有http用来发送请求,async提供Future抽象类以及convert用来将json数据转换为dart里面的对象。
首先使用flutter create xxx 命令或者 IDEA 新建一个Flutter项目,去掉示例代码,将需要的依赖引入
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
根据接口返回数据定义好需要的数据类,例如接口返回的数据为一个数据列表
{
"request_hash": "request:top:de22cb0aea0daa23a9e82809cf45d652ccce8ef3",
"request_cached": false,
"request_cache_expiry": 43200,
"top": [{
"mal_id": 32281,
"rank": 1,
"title": "Kimi no Na wa.",
"url": "https:\/\/myanimelist.net\/anime\/32281\/Kimi_no_Na_wa",
"image_url": "https:\/\/cdn.myanimelist.net\/images\/anime\/5\/87048.jpg?s=2bca128fcb9dfd6d0908f3d9986576c6",
"type": "Movie",
"episodes": 1,
"airing_start": "Aug 2016",
"airing_end": "Aug 2016",
"members": 947231,
"score": 9.14
}, {
"mal_id": 15335,
"rank": 3,
"title": "Gintama Movie 2: Kanketsu-hen - Yorozuya yo Eien Nare",
"url": "https:\/\/myanimelist.net\/anime\/15335\/Gintama_Movie_2__Kanketsu-hen_-_Yorozuya_yo_Eien_Nare",
"image_url": "https:\/\/cdn.myanimelist.net\/images\/anime\/10\/51723.jpg?s=27cd24446486572fb64c42a689d38902",
"type": "Movie",
"episodes": 1,
"airing_start": "Jul 2013",
"airing_end": "Jul 2013",
"members": 121401,
"score": 9.01
}, {
"mal_id": 34537,
"rank": 50,
"title": "Yoru wa Mijikashi Arukeyo Otome",
"url": "https:\/\/myanimelist.net\/anime\/34537\/Yoru_wa_Mijikashi_Arukeyo_Otome",
"image_url": "https:\/\/cdn.myanimelist.net\/images\/anime\/2\/86940.jpg?s=838b10398449d3354db5fb604b3b1b17",
"type": "Movie",
"episodes": 1,
"airing_start": "Apr 2017",
"airing_end": "Apr 2017",
"members": 45656,
"score": 8.32
}]
}
根据需要的数据字段定义 Animate 类, Animate.fromJson 方法使用json数据生成一个Animate实例
class Animate {
final int rank;
final String imgUrl;
final String title;
final double score;
final String url;
final String airingStart;
final String airingEnd;
Animate({
this.rank,
this.imgUrl,
this.title,
this.score,
this.url,
this.airingStart,
this.airingEnd,
});
factory Animate.fromJson(Map<String, dynamic> json) {
return Animate(
rank: json['rank'] as int,
imgUrl: json['image_url'] as String,
title: json['title'] as String,
score: json['score'] as double,
url: json['url'] as String,
airingStart: json['airing_start'] as String,
airingEnd: json['airing_end'] as String,
);
}
}
之后使用http发送请求,定义一个StatefulWidget以及它的State类,定义一个变量存储数据,定义获取数据的方法,然后重写类的initState方法,在initState方法里面调用请求数据的方法
拿到数据后就可以进行数据渲染了,定义一个StatelessWidget类来作为列表中的每一项,这个类需要一个Animate类的实例来填充数据
最后使用ListView.builder方法生成ListView
完成效果如图
完整代码
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
//import 'package:url_launcher/url_launcher.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter get datas",
theme: ThemeData(primarySwatch: Colors.deepPurple),
debugShowCheckedModeBanner: false,
home: AppHomePage(),
);
}
}
class Animate {
final int rank;
final String imgUrl;
final String title;
final double score;
final String url;
final String airingStart;
final String airingEnd;
Animate({
this.rank,
this.imgUrl,
this.title,
this.score,
this.url,
this.airingStart,
this.airingEnd,
});
factory Animate.fromJson(Map<String, dynamic> json) {
return Animate(
rank: json['rank'] as int,
imgUrl: json['image_url'] as String,
title: json['title'] as String,
score: json['score'] as double,
url: json['url'] as String,
airingStart: json['airing_start'] as String,
airingEnd: json['airing_end'] as String,
);
}
}
class AnimateCard extends StatelessWidget {
Animate animate;
AnimateCard(this.animate);
@override
Widget build(BuildContext context) {
return Card(
child: InkWell(
onTap: () {
print(animate.url);
},
child: ListTile(
contentPadding: EdgeInsets.only(left: 10.0, right: 10.0),
leading: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 6.0),
child: Text(
animate.rank < 10 ? '0${animate.rank.toString()}' : animate.rank.toString()),
),
Image(image: NetworkImage(animate.imgUrl), width: 45.0, height: 45.0),
],
),
title: Padding(
padding: EdgeInsets.only(bottom: 10.0),
child: Text(
animate.title,
maxLines: 2,
textAlign: TextAlign.start,
overflow: TextOverflow.ellipsis,
style: TextStyle(color: Colors.deepPurple, fontSize: 16.0),
),
),
subtitle: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 4.0),
child: Text(
"上映日期:",
style: TextStyle(fontSize: 12.0),
),
),
Padding(
padding: const EdgeInsets.only(right: 4.0),
child: Text(
animate.airingStart,
style: TextStyle(fontSize: 12.0),
),
),
Padding(
padding: const EdgeInsets.only(right: 4.0),
child: Text(
"下映日期:",
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 12.0),
),
),
Text(
animate.airingEnd,
style: TextStyle(fontSize: 12.0),
),
],
),
trailing: Text(
animate.score.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.green,
),
),
),
),
);
}
}
class AppHomePage extends StatefulWidget {
@override
_AppHomePageState createState() => _AppHomePageState();
}
class _AppHomePageState extends State<AppHomePage> {
List movies;
Future getMovies({String type = 'anime', int page = 1, String subtype = 'movie'}) async {
final String url = "https://api.jikan.moe/top/$type/$page/$subtype";
final response = await http.get(url);
if (response.statusCode == 200) {
List top = json.decode(response.body)['top'];
setState(() {
movies = top.map((json) => Animate.fromJson(json)).toList();
});
} else {
print("err code $response.statusCode");
}
}
@override
void initState() {
super.initState();
getMovies();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Top Animate Movies'),
),
body: movies == null
? Center(child: CircularProgressIndicator())
: Padding(
padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 10.0),
child: ListView.builder(
itemCount: movies.length,
itemBuilder: (BuildContext context, int index) {
return AnimateCard(movies[index]);
},
),
),
);
}
}
获取不到数据记得Vpn翻墙
作者:轻剑快马 链接:juejin.im/post/5b7ac5… 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。