美文网首页
三、Flutter之StatefulWidget和网络请求

三、Flutter之StatefulWidget和网络请求

作者: 夏_Leon | 来源:发表于2019-02-25 15:00 被阅读0次

    之前学习中使用的都是StatelessWidget,是不可变的,这意味着它们的属性不能改变。而当我们需要一个动态的属性可变的控件,就需要用到StatefulWidget

    StatefulWidget持有的状态可能在 widget 生命周期中发生变化,实现一个 stateful widget 至少需要两个类:1)一个 StatefulWidget 类;2)一个 State 类,StatefulWidget 类本身是不变的,但是 State 类在 widget 生命周期中始终存在。

    在这一步,你将添加一个 StatefulWidget-ListViewSample,它会创建自己的状态类-_ListViewSampleState,然后你需要将 ListViewSample 内嵌到已有的App里。

    先导入网络请求的包:

    import 'dart:io';
    import 'dart:convert';
    

    列表展示及网络请求核心代码:

    //StatefulWidget申明
    class ListViewSample extends StatefulWidget {
      @override
      State createState() {
        return new _ListViewSampleState();
      }
    }
    
    //StatefulWidget对应的State
    class _ListViewSampleState extends State<ListViewSample> {
      List _listItems; //私有的list数据
    
      @override
      void initState() {
        super.initState();
        //初始化时即进行数据请求
        getNewMovie();
      }
    
      //请求豆瓣当前热门电影
      getNewMovie() async {
        var httpClient = new HttpClient();
        //网络请求,{}里可以添加参数
        var uri = new Uri.http('api.douban.com', '/v2/movie/in_theaters', {});
        //flutter是单线程,用httpclient进行网络请求时要用await关键字,并且此时返回的都是Future对象s
        var request = await httpClient.getUrl(uri);
        var response = await request.close();
    
        if (response.statusCode == 200) {
          var responseBody = await response.transform(utf8.decoder).join();
          //注意很多教程里json转换用的是JSON.decode,然而在18年底的一个版本中,把常量都改为小写了。现在都是用json.decode
          Map<String, dynamic> map = json.decode(responseBody);
          print('refresh movie list ');
          setState(() {
            _listItems = new List();
            for (dynamic movie in map['subjects']) {
              _listItems.add(movie);
            }
          });
        } else {
          print("http error ${response.statusCode}");
        }
      }
    
      @override
      Widget build(BuildContext context) {
        //还没请求到数据的时候显示加载中
        if (_listItems == null) {
          return new Center(
            heightFactor: 6,
            child: new Text('加载中...'),
          );
        }
    
        //请求到数据后显示列表
        return new Expanded(
          child: new ListView.builder(
            scrollDirection: Axis.vertical,
            itemCount: _listItems.length,
            itemBuilder: (context, index) {
              return movieItem(context, index);
            },
          ),
        );
      }
    
      //列表单元的UI封装
      Widget movieItem(BuildContext context, int index) {
        return new Column(
          children: <Widget>[
            //分割线
            new Divider(),
    
            //包裹一个GestureDetector,响应点击事件
            new GestureDetector(
              //点击item的时候也再请求数据
              onTap: getNewMovie,
              //item容器
              child: new Container(
                padding: const EdgeInsets.all(8.0),
                //一级Row布局
                child: new Row(
                  //右边布局顶对齐
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    //显示电影图片
                    new Image.network(
                      _listItems[index]['images']['small'],
                      width: 100,
                    ),
    
                    //右边布局
                    new Column(
                      mainAxisAlignment: MainAxisAlignment.end,
                      children: <Widget>[
                        //电影名
                        new Container(
                          padding: EdgeInsets.all(8.0),
                          width: 200,
                          child: new Text(
                            _listItems[index]['title'],
                            style: new TextStyle(
                              color: Colors.blueAccent,
                            ),
                            overflow: TextOverflow.clip,
                            textAlign: TextAlign.left,
                          ),
                        ),
    
                        //评分
                        new Container(
                          padding: EdgeInsets.all(8.0),
                          width: 200,
                          child: new Text(
                            '评分:' +
                                _listItems[index]['rating']['average'].toString(),
                            style: new TextStyle(
                              color: Colors.orange,
                            ),
                            overflow: TextOverflow.clip,
                            textAlign: TextAlign.left,
                          ),
                        ),
    
                        //导演
                        new Container(
                          padding: EdgeInsets.all(8.0),
                          width: 200,
                          child: new Text(
                            '导演:' + _listItems[index]['directors'][0]['name'],
                            style: new TextStyle(
                              color: Colors.blueAccent,
                            ),
                            overflow: TextOverflow.clip,
                            textAlign: TextAlign.left,
                          ),
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            ),
          ],
        );
      }
    }
    

    可以看到在Flutter中UI的嵌套层级非常深,而在Android中如果用约束布局,一两层就可以搞定了,这方面是很不习惯。但是代码量来说Flutter是远少于Android的,不需要单独写xml文件,网络请求库的使用非常简单,列表不需要写Adapter那么麻烦。
    Item单元的代码中我加了GestureDetector,这是为了添加点击事件,在点击时刷新数据。这种在控件内部修改state的方式比较简单,如果是在控件外修改state就比较麻烦了。

    这里的网络请求用的是自带的httpclient,代码比较简单,不需要进行一大堆设置就能先跑起来,要注意Dart是单线程的,所有耗时任务都要加入async关键词放入延时任务里,具体参考 异步async、await和Future的使用技巧

    相关文章

      网友评论

          本文标题:三、Flutter之StatefulWidget和网络请求

          本文链接:https://www.haomeiwen.com/subject/xtpsyqtx.html