利用Flutter写一个跨平台的果核APP(3)——网络请求

前言

紧接上文界面篇,上文中在构建布局的时候由于是直接将文字图片显示出来的,因此消息类Message,和日知录类One都是采用的无状态的StatelessWidget类,此次咱们须要调用接口,而后将返回的数据动态的显示到那两个控件上去,StatelessWidget类已经没法知足需求了,这个时候咱们须要使用Flutter提供的另外一个类StatefulWidget,一旦控件继承了这个类则说明该空间是一个有状态的控件,能够进行动态更新等。html

到目前为止,咱们只使用了无状态的widget。无状态widget从它们的父widget接收参数, 它们被存储在final型的成员变量中。 当一个widget被要求构建时,它使用这些存储的值做为参数来构建widget。 为了构建更复杂的体验 - 例如,以更有趣的方式对用户输入作出反应 - 应用程序一般会携带一些状态。 Flutter使用StatefulWidget来知足这种需求。StatefulWidget是特殊的widget,它知道如何生成State对象,而后用它来保持状态。git

解析

那么该如何建立一个有状态的widget,同时又如何进行网络请求并对控件的状态进行更新呢?咱们一个一个的解决。github

  1. 建立一个有状态的Message控件
//消息
class Message extends StatefulWidget {
  @override
  MessageState createState() => new MessageState();
}

class MessageState extends State<Message> {

  @override
  Widget build(BuildContext context) {
       //这里建立页面
  }
}
复制代码

build函数的内容其实和以前建立无状态的Message控件的是同样的,直接复制来就好json

@override
  Widget build(BuildContext context) {
    return new Padding(
      padding: new EdgeInsets.all(18.0),
      child: new Column(
        children: <Widget>[
          new Container(
            child: new Row(
              children: <Widget>[
                new Icon(
                  Icons.message,
                  color: Colors.black26,
                  size: 17.0,
                ),
                new Container(
                  margin: new EdgeInsets.only(left: 5.0),
                  child: new Text(
                    '消息',
                    style: new TextStyle(color: Color(0xFF888888)),
                  ),
                )
              ],
            ),
          ),
          new Divider(
            color: Color(0xFF888888),
          ),
          new Container(
            margin: new EdgeInsets.all(10.0),
            child: new Text("这里是消息"),
          ),
          new Divider(
            color: Color(0xFF888888),
          )
        ],
      ),
    );
  }
复制代码
  1. 进行网络请求并更新控件 在flutter中进行网络请求有两种方式
  • 在Flutter中发起HTTP网络请求
  • 开源库——dio 在这里推荐使用第二种,dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时等。和安卓里的OkHttp相似。具体用法能够查看传送门,文档写的很详细。 回到该应用,在这里咱们须要建立一个getMessage()方法,并经过get请求相应的接口,而后对返回的res进行解析便可,以下所示:
String message = "这里是消息模块";

  @override
  void initState() {
    super.initState();
    getMessage();
  }

  //获取消息
  void getMessage() {
    Dio().get(Constant.GET_MSG).then((res) {
      if (res.statusCode == 200) {
        int code = res.data['code'];
        if (code == 200) {
          String info = res.data['info'][0];
          print(info);
          setState(() {
            message = info;
          });
        }
      }
    });
  }
复制代码

说明一下:bash

  1. 调用setState()是相当重要的,由于它告诉框架控件的状态已经改变,控件应该从新绘制。在这里的做用就是将以前设置的message变量变为从接口中获取的变量。
  2. json的解析,推荐阅读《在 Flutter 中解析复杂的 JSON》
  3. 咱们若是须要在控件一开始渲染的时候就要发送网络请求,须要在initState()函数中调用getMessage()方法

该页代码

由于日知录部分的基本上也是网络请求和动态渲染控件,道理是一致的,因此我就直接在这里贴上代码了。网络

import 'package:flutter/material.dart';
import 'package:flutter_guohe/common/eventBus.dart';
import 'package:dio/dio.dart';
import 'package:flutter_guohe/views/customview.dart';
import 'package:flutter_guohe/utils/constant.dart';

class Today extends StatefulWidget {
  @override
  TodayState createState() => new TodayState();
}

class TodayState extends State<Today> {
  //打开drawer
  void openDrawer() {
    eventBus.fire(new EventOpenDrawer(true));
  }

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        appBar: new AppBar(
          leading: new IconButton(
            icon: Icon(Icons.home),
            onPressed: () {
              //打开drawer
              openDrawer();
            },
          ),
          title: new Text("今日"), //设置标题内容
          backgroundColor: Color.fromARGB(255, 119, 136, 213), //设置appbar背景颜色
          centerTitle: true, //设置标题是否局中
        ),
        body: new ListView(
          children: <Widget>[
            new Header(), //头部
            new BigDivider(),
            new TodayKb(), //今日课表
            new BigDivider(),
            new Message(), //消息
            new BigDivider(),
            new One() //日知录
          ],
        ),
      ),
    );
  }
}

//首页的头部信息
class Header extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      height: 100.0,
      margin: new EdgeInsets.all(8.0),
      child: new Row(
        children: <Widget>[
          new Expanded(
            child: new Column(
              children: <Widget>[
                //头像
                new Container(
                  width: 60.0,
                  height: 60.0,
                  margin: new EdgeInsets.all(8.0),
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      image: new AssetImage('assets/imgs/ic_menu_score.png'),
                      //从Assets加载图片
                      fit: BoxFit.cover,
                    ),
                    shape: BoxShape.circle,
                  ),
                ),
                new Text(
                  '查成绩',
                  textAlign: TextAlign.center,
                )
              ],
            ),
            flex: 1,
          ),
          new Expanded(
            child: new Column(
              children: <Widget>[
                //头像
                new Container(
                  width: 60.0,
                  height: 60.0,
                  margin: new EdgeInsets.all(8.0),
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      image: new AssetImage('assets/imgs/ic_menu_pe.png'),
                      //从Assets加载图片
                      fit: BoxFit.cover,
                    ),
                    shape: BoxShape.circle,
                  ),
                ),
                new Text(
                  '查体育',
                  textAlign: TextAlign.center,
                )
              ],
            ),
            flex: 1,
          ),
          new Expanded(
            child: new Column(
              children: <Widget>[
                //头像
                new Container(
                  width: 60.0,
                  height: 60.0,
                  margin: new EdgeInsets.all(8.0),
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      image: new AssetImage('assets/imgs/ic_menu_bus.png'),
                      //从Assets加载图片
                      fit: BoxFit.cover,
                    ),
                    shape: BoxShape.circle,
                  ),
                ),
                new Text(
                  '查校车',
                  textAlign: TextAlign.center,
                )
              ],
            ),
            flex: 1,
          ),
          new Expanded(
            child: new Column(
              children: <Widget>[
                //头像
                new Container(
                  width: 60.0,
                  height: 60.0,
                  margin: new EdgeInsets.all(8.0),
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      image: new AssetImage('assets/imgs/ic_menu_system.png'),
                      //从Assets加载图片
                      fit: BoxFit.cover,
                    ),
                    shape: BoxShape.circle,
                  ),
                ),
                new Text(
                  '校园系统',
                  textAlign: TextAlign.center,
                )
              ],
            ),
            flex: 1,
          ),
          new Expanded(
            child: new Column(
              children: <Widget>[
                //头像
                new Container(
                  width: 60.0,
                  height: 60.0,
                  margin: new EdgeInsets.all(8.0),
                  decoration: BoxDecoration(
                    image: DecorationImage(
                      image: new AssetImage('assets/imgs/ic_menu_more.png'),
                      //从Assets加载图片
                      fit: BoxFit.cover,
                    ),
                    shape: BoxShape.circle,
                  ),
                ),
                new Text(
                  '更多',
                  textAlign: TextAlign.center,
                )
              ],
            ),
            flex: 1,
          ),
        ],
      ),
    );
  }
}

//今日课表
class TodayKb extends StatefulWidget {
  @override
  TodayKbState createState() => new TodayKbState();
}

class TodayKbState extends State<TodayKb> {
  @override
  Widget build(BuildContext context) {
    //跳转至课表
    _toKb() {
      print('跳转至课表');
    }

    return new Padding(
      padding: new EdgeInsets.all(18.0),
      child: new Column(
        children: <Widget>[
          new Container(
            child: new Row(
              children: <Widget>[
                new Icon(
                  Icons.camera,
                  color: Colors.black26,
                  size: 17.0,
                ),
                new Container(
                  margin: new EdgeInsets.only(left: 5.0),
                  child: new Text(
                    '今日课表',
                    style: new TextStyle(color: Color(0xFF888888)),
                  ),
                )
              ],
            ),
          ),
          new Divider(
            color: Color(0xFF888888),
          ),
          new Container(
            margin: new EdgeInsets.only(top: 30.0, bottom: 2.0),
            child: new Text("今天竟然没有课~" + "\uD83D\uDE01"),
          ),
          new GestureDetector(
            child: new Container(
              margin: new EdgeInsets.only(top: 30.0, bottom: 2.0),
              child: new Text('点我查看完整课表',
                  style: new TextStyle(
                      color: Color(
                        0xFF888888,
                      ),
                      fontSize: 12.0)),
            ),
            onTap: _toKb,
          ),
        ],
      ),
    );
  }
}

//消息
class Message extends StatefulWidget {
  @override
  MessageState createState() => new MessageState();
}

class MessageState extends State<Message> {
  String message = "这里是消息模块";

  @override
  void initState() {
    super.initState();
    getMessage();
  }

  //获取消息
  void getMessage() {
    Dio().get(Constant.GET_MSG).then((res) {
      if (res.statusCode == 200) {
        int code = res.data['code'];
        if (code == 200) {
          String info = res.data['info'][0];
          print(info);
          setState(() {
            message = info;
          });
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Padding(
      padding: new EdgeInsets.all(18.0),
      child: new Column(
        children: <Widget>[
          new Container(
            child: new Row(
              children: <Widget>[
                new Icon(
                  Icons.message,
                  color: Colors.black26,
                  size: 17.0,
                ),
                new Container(
                  margin: new EdgeInsets.only(left: 5.0),
                  child: new Text(
                    '消息',
                    style: new TextStyle(color: Color(0xFF888888)),
                  ),
                )
              ],
            ),
          ),
          new Divider(
            color: Color(0xFF888888),
          ),
          new Container(
            margin: new EdgeInsets.all(10.0),
            child: new Text(message),
          ),
          new Divider(
            color: Color(0xFF888888),
          )
        ],
      ),
    );
  }
}

//日知录
class One extends StatefulWidget {
  @override
  OneState createState() => new OneState();
}

class OneState extends State<One> {
  String date = "2018/09/14";
  String imgUrl = 'http://image.wufazhuce.com/Fn5E1UnrcvN0jwFRiOtDZ2WnQa4N';
  String imgAuthor = "Fahmi Ramadhan";
  String imgKind = "摄影";
  String url = "http://m.wufazhuce.com/one/2202";
  String word = "恋爱不是用谈的,是坠入的。";
  String wordFrom = "《寂寞东京铁塔》";

  //获取日知录的内容
  void getOneContent() {
    FormData formData = new FormData.from(
        {"TransCode": "030111", "OpenId": "123456789", "Body": "123456789"});
    Dio().post(Constant.ONE, data: formData).then((res) {
      setState(() {
        date = res.data['Body']['date']
            .toString()
            .split(" ")[0]
            .replaceAll("-", "/");
        imgUrl = res.data['Body']['img_url'];
        imgAuthor = res.data['Body']['img_author'];
        imgKind = res.data['Body']['img_kind'];
        url = res.data['Body']['url'];
        word = res.data['Body']['word'];
        wordFrom = res.data['Body']['word_from'];
      });
    });
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();

    getOneContent();
  }

  @override
  Widget build(BuildContext context) {
    return new Padding(
      padding: new EdgeInsets.all(18.0),
      child: new Column(
        children: <Widget>[
          new Container(
            child: new Row(
              children: <Widget>[
                new Icon(
                  Icons.email,
                  color: Colors.black26,
                  size: 17.0,
                ),
                new Container(
                  margin: new EdgeInsets.only(left: 5.0),
                  child: new Text(
                    '日知录',
                    style: new TextStyle(color: Color(0xFF888888)),
                  ),
                )
              ],
            ),
          ),
          new Divider(
            color: Color(0xFF888888),
          ),
          new Container(
            margin: new EdgeInsets.all(10.0),
            child: new Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                new Text(
                  date,
                  style: new TextStyle(color: Color(0xFF888888)),
                ),
                new Margin(indent: 6.0),
                new Image(image: new NetworkImage(imgUrl)),
                new Margin(indent: 6.0),
                new Text(
                  imgAuthor + " | " + imgKind,
                  style: new TextStyle(color: Color(0xFF888888)),
                ),
                new Margin(indent: 6.0),
                new Text(
                  word,
                  textAlign: TextAlign.center,
                  style: new TextStyle(color: Color(0xFF888888)),
                ),
                new Margin(indent: 6.0),
                new Text(
                  wordFrom,
                  style: new TextStyle(color: Color(0xFF888888)),
                )
              ],
            ),
          ),
          new Divider(
            color: Color(0xFF888888),
          )
        ],
      ),
    );
  }
}
复制代码