Flutter之对接接口并显示
Fluter对接接口并显示的整个过程还是比较复杂的,我花了比较长的时间进行研究,以对接查询接口为例,整理如下:
若接口的返回数据为:
[{"id":1,"question":"世界上最大的海洋是?","type":"radio","options":"北冰洋,太平洋,印度洋","rightAnswer":"太平洋"},{"id":2,"question":"下面这张图是谁?","type":"radio","options":"陈独秀,李大钊,叶挺,胡适,蔡锷,胡宗南","rightAnswer":"李大钊","pic":"https://z3.ax1x.com/2021/05/22/gOiiKH.jpg"},{"id":3,"question":"要慎重对待朋友交往,坚持择善而交,多同()交朋友,注意净化自己的社交圈。","type":"radio","options":"普通群众,基层干部,先进模范,专家学者","rightAnswer":"普通群众"},{"id":4,"question":"1927年9月29日,秋收起义各部队到达江西永新县三湾村,在毛领导下进行了改编,史称三湾改编。三湾改编的措施( )。","type":"checkbox","checkboxOptions":[{"id":1,"title":"确立了毛在党中央和红军的领导地位","isRight":0,"quizId":4},{"id":2,"title":"开始改变旧军队的习气和不良作风","isRight":1,"quizId":4},{"id":3,"title":"从组织上确立了党对军队的领导","isRight":1,"quizId":4},{"id":4,"title":"是建设无产阶级领导的新型人民军队的重要开端","isRight":1,"quizId":4}]},{"id":5,"question":"通过延安整风,中共初步确立了密切联系群众的思想路线,将马克思主义中国化的第一个理论成果确定为党的指导思想。","type":"radio","options":"对,错","rightAnswer":"错"}]
1.在pubspec.yaml文件中增加dio依赖,然后安装依赖
如:
dependencies: flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.3 fluttertoast: ^3.0.3 shared_preferences: ^0.5.1 dio: 3.0.9
2.新建一个异步函数,用getDioQuiz函数进行网络请求,使用await等待拿到结果,最后函数返回一个List。
Future<List> fetchData() async{ List arr = await getDioQuiz();return arr; }
getDioQuiz函数代码如下,quizList即为需要显示的列表:
static Future<List> getDioQuiz() async{ Dio dio = new Dio(); Response response = await dio.get(Global.host + "getAllQuiz"); List<Quiz> quizList = (response.data as List<dynamic>).map((e) => Quiz.fromJson((e as Map<String,dynamic>))).toList(); return quizList; }
其中Global.host是一个静态全局变量
global.dart代码如下:
class Global{ static bool isChangeQuizOrder = true; static bool isChangeOptionOrder = true; static String dropdownValue = 'all'; static String host = "http://1.15.186.160:8003/quiz/"; }
3.新建Quiz和Option对应的实体类quiz.dart和option.dart。
quiz.dart
import 'option.dart'; class Quiz { int id; String question; String type; String options; String rightAnswer; String pic; List<Option> checkboxOptions; Quiz({this.id, this.question, this.type, this.options, this.rightAnswer, this.pic, this.checkboxOptions}); Quiz.fromJson(Map<String, dynamic> json) { id = json['id']; question = json['question']; type = json['type']; options = json['options']; rightAnswer = json['rightAnswer']; pic = json['pic']; if (json['checkboxOptions'] != null) { checkboxOptions = new List<Option>(); json['checkboxOptions'].forEach((v) { checkboxOptions.add(new Option.fromJson(v)); }); } } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['id'] = this.id; data['question'] = this.question; data['type'] = this.type; data['options'] = this.options; data['rightAnswer'] = this.rightAnswer; data['pic'] = this.pic; data['checkboxOptions'] = this.checkboxOptions; if (this.checkboxOptions != null) { data['checkboxOptions'] = this.checkboxOptions.map((v) => v.toJson()).toList(); } return data; } }
option.dart
class Option { int id; String title; int isRight; int quizId; bool isSelected; Option({this.id, this.title, this.isRight, this.quizId, this.isSelected=false}); factory Option.fromJson(Map<String, dynamic> json) { return Option( id: json['id'], title: json['title'], isRight: json['isRight'], quizId: json['quizId'], ); } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['id'] = this.id; data['title'] = this.title; data['isRight'] = this.isRight; data['quizId'] = this.quizId; return data; } }
4.在build函数中加上FutureBuilder组件等待接口请求返回数据
@override Widget build(BuildContext context) { return FutureBuilder( future: fetchData(), builder: (context, snapshot) { if (snapshot.hasData) { return Scaffold( appBar: AppBar( title: Text('问题${_count + 1}'), ), body: Container( child: ListView(children: <Widget>[ Column( children: <Widget>[ Container( child: Text((list[_count] as Quiz).question, style: TextStyle(fontSize: 20, color: Colors.black)), margin: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 20.0), ), showPic(), Column(children: generateOptions()), ], ) ]), ) ); } return Text(''); } ); }
return Text('')为请求接口时显示的页面,可以修改为:
return Scaffold( body: Center( child: Text('页面加载中……'), ), );
5.由于build函数会在程序运行过程中多次执行,导致fetchData函数也被多次执行。
要想让fetchData函数只被执行一次。我们可以在类里新建状态值
Future _fetchData;
在initState进行调用
@override void initState(){ _fetchData = fetchData(); super.initState(); }
再换掉build里future对应的值
@override Widget build(BuildContext context) { return FutureBuilder( future: _fetchData, builder: (context, snapshot) { if (snapshot.hasData) { return Scaffold( appBar: AppBar( title: Text('问题${_count + 1}'), ), body: Container( child: ListView(children: <Widget>[ Column( children: <Widget>[ Container( child: Text((list[_count] as Quiz).question, style: TextStyle(fontSize: 20, color: Colors.black)), margin: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 20.0), ), showPic(), Column(children: generateOptions()), ], ) ]), ) ); } return Text(''); } ); }
即可。