利用Flutter寫(xiě)一個(gè)跨平臺(tái)的果核APP(3)——網(wǎng)絡(luò)請(qǐng)求

前言

緊接上文界面篇,上文中在構(gòu)建布局的時(shí)候因?yàn)槭侵苯訉⑽淖謭D片顯示出來(lái)的,所以消息類Message,和日知錄類One都是采用的無(wú)狀態(tài)的StatelessWidget類,這次我們需要調(diào)用接口,然后將返回的數(shù)據(jù)動(dòng)態(tài)的顯示到那兩個(gè)控件上去,StatelessWidget類已經(jīng)無(wú)法滿足需求了,這個(gè)時(shí)候我們需要使用Flutter提供的另一個(gè)類StatefulWidget,一旦控件繼承了這個(gè)類則說(shuō)明該空間是一個(gè)有狀態(tài)的控件,可以進(jìn)行動(dòng)態(tài)更新等。

到目前為止,我們只使用了無(wú)狀態(tài)的widget。無(wú)狀態(tài)widget從它們的父widget接收參數(shù), 它們被存儲(chǔ)在final型的成員變量中。 當(dāng)一個(gè)widget被要求構(gòu)建時(shí),它使用這些存儲(chǔ)的值作為參數(shù)來(lái)構(gòu)建widget。
為了構(gòu)建更復(fù)雜的體驗(yàn) - 例如,以更有趣的方式對(duì)用戶輸入做出反應(yīng) - 應(yīng)用程序通常會(huì)攜帶一些狀態(tài)。 Flutter使用StatefulWidget來(lái)滿足這種需求。StatefulWidget是特殊的widget,它知道如何生成State對(duì)象,然后用它來(lái)保持狀態(tài)。

解析

那么該如何創(chuàng)建一個(gè)有狀態(tài)的widget,同時(shí)又如何進(jìn)行網(wǎng)絡(luò)請(qǐng)求并對(duì)控件的狀態(tài)進(jìn)行更新呢?我們一個(gè)一個(gè)的解決。

  1. 創(chuàng)建一個(gè)有狀態(tài)的Message控件
//消息
class Message extends StatefulWidget {
  @override
  MessageState createState() => new MessageState();
}

class MessageState extends State<Message> {

  @override
  Widget build(BuildContext context) {
       //這里創(chuàng)建頁(yè)面
  }
}

build函數(shù)的內(nèi)容其實(shí)和之前創(chuàng)建無(wú)狀態(tài)的Message控件的是一樣的,直接復(fù)制來(lái)就好

@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. 進(jìn)行網(wǎng)絡(luò)請(qǐng)求并更新控件
    在flutter中進(jìn)行網(wǎng)絡(luò)請(qǐng)求有兩種方式
  • 在Flutter中發(fā)起HTTP網(wǎng)絡(luò)請(qǐng)求
  • 開(kāi)源庫(kù)——dio
    在這里推薦使用第二種,dio是一個(gè)強(qiáng)大的Dart Http請(qǐng)求庫(kù),支持Restful API、FormData、攔截器、請(qǐng)求取消、Cookie管理、文件上傳/下載、超時(shí)等。和安卓里的OkHttp類似。具體用法可以查看傳送門(mén),文檔寫(xiě)的很詳細(xì)。
    回到該應(yīng)用,在這里我們需要?jiǎng)?chuàng)建一個(gè)getMessage()方法,并通過(guò)get請(qǐng)求相應(yīng)的接口,然后對(duì)返回的res進(jìn)行解析即可,如下所示:
  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;
          });
        }
      }
    });
  }

說(shuō)明一下:

  1. 調(diào)用setState()是至關(guān)重要的,因?yàn)樗嬖V框架控件的狀態(tài)已經(jīng)改變,控件應(yīng)該重新繪制。在這里的作用就是將之前設(shè)置的message變量變?yōu)閺慕涌谥蝎@取的變量。
  2. json的解析,推薦閱讀《在 Flutter 中解析復(fù)雜的 JSON》
  3. 我們?nèi)绻枰诳丶婚_(kāi)始渲染的時(shí)候就要發(fā)送網(wǎng)絡(luò)請(qǐng)求,需要在initState()函數(shù)中調(diào)用getMessage()方法

該頁(yè)代碼

因?yàn)槿罩洸糠值幕旧弦彩蔷W(wǎng)絡(luò)請(qǐng)求和動(dòng)態(tài)渲染控件,道理是一致的,所以我就直接在這里貼上代碼了。

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> {
  //打開(kāi)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: () {
              //打開(kāi)drawer
              openDrawer();
            },
          ),
          title: new Text("今日"), //設(shè)置標(biāo)題內(nèi)容
          backgroundColor: Color.fromARGB(255, 119, 136, 213), //設(shè)置appbar背景顏色
          centerTitle: true, //設(shè)置標(biāo)題是否局中
        ),
        body: new ListView(
          children: <Widget>[
            new Header(), //頭部
            new BigDivider(),
            new TodayKb(), //今日課表
            new BigDivider(),
            new Message(), //消息
            new BigDivider(),
            new One() //日知錄
          ],
        ),
      ),
    );
  }
}

//首頁(yè)的頭部信息
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(
                  '查成績(jī)',
                  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(
                  '校園系統(tǒng)',
                  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) {
    //跳轉(zhuǎn)至課表
    _toKb() {
      print('跳轉(zhuǎn)至課表');
    }

    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("今天居然沒(méi)有課~" + "\uD83D\uDE01"),
          ),
          new GestureDetector(
            child: new Container(
              margin: new EdgeInsets.only(top: 30.0, bottom: 2.0),
              child: new Text('點(diǎn)我查看完整課表',
                  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 = "戀愛(ài)不是用談的,是墜入的。";
  String wordFrom = "《寂寞東京鐵塔》";

  //獲取日知錄的內(nèi)容
  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),
          )
        ],
      ),
    );
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容