Flutter—使用网络请求的页面搭建流程、State生命周期、一些组件的应用

使用网络请求的页面搭建流程

​ 在开发APP时,我们常常会遇到如下场景:进入一个页面后,要先进行网络调用,然后使用调用返回的数据进行页面渲染。

​ 这种页面搭建流程大致为:调用网络请求,获得json格式的数据—解析获得的数据为Dart类 — 将Dart数据传回UI。在返回数据前,可以在页面先放置一个加载动画;获得数据后,使用数据进行进行页面重绘。

网络请求

​ Flutter的网络请求常常使用的库有httpdio,其中dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时、自定义适配器等。dio的详细介绍与使用方法可以参见github-dio官方文档

  • 在pubspec.yaml中引入包依赖

    dependencies:
    dio: ^3.x.x // 请使用pub上3.0.0分支的最新版本
  • 极简示例

    import 'package:dio/dio.dart';
    void getHttp() async {
    try {
    Response response = await Dio().get("http://www.baidu.com");
    print(response);
    } catch (e) {
    print(e);
    }
    }

数据解析

​ 当调用Dio.get()方法时,可以从网络获得json数据,我们可以将这些数据进行解析处理,方便UI搭建的使用。 实例如下:

//该函数从调用服务器某一个接口,获得json数据,并将解析后的Dart model返回。
Future<Course> getCourse(String studentID) async {
Dio dio = new Dio();
Response response;
response = await dio.request(
'http://www.baidu.com',//将此替换为后端服务器地址
options: Options(method: "GET", responseType: ResponseType.plain),
);
String ss = response.data;
dynamic jsonList = json.decode(ss);
Course tempStr = new Course.fromJson(jsonList);//将json解析为Dart类,
return tempStr;
}

Course.fromJson的实现有很多种方式,可以手写或者自动生成。在此推荐一个json-Dart 转换的网页json to Dart。该网页可以自动根据给定的json数据生成Dart类。例如对于如下格式的json数据:

{
"course_name": "计算机网络",
"department": "计算机学院"
}

生成的Dart 类为:

class course {
String courseName;
String department; course({this.courseName, this.department}); course.fromJson(Map<String, dynamic> json) {
courseName = json['course_name'];
department = json['department'];
} Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['course_name'] = this.courseName;
data['department'] = this.department;
return data;
}
}

FutureBuilder页面渲染

​ 在实现网络请求的调用和数据解析后,我们需要把获得的数据应用到UI的渲染中。此时就要用到``FutureBuilder`。

FutureBuilder是一个将异步操作和异步UI更新结合在一起的类,通过它我们可以将网络请求,数据库读取等的结果更新的页面上。其构造方法如下:

FutureBuilder({
Key key, Future<T> future, //表示此构建器当前连接的异步计算。
T initialData,
@required
AsyncWidgetBuilder<T> builder //是一个基于异步交互构建widget的函数,这个函数接受两个参数`BuildContext context`与 `AsyncSnapshot<T> snapshot`,并应该返回一个widget。其中异步计算获得的数据就保存在`snapshot.data`中,在builder中可以通过`snapshot.data`获得异步数据。
})

一个使用实例

//网络调用未返回数据时,返回加载动画;返回数据后展示返回数据的'course_name'值。
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('主题'),
),
body: FutureBuilder<CommonModel>(
future: getCourse(),//调用上面数据解析部分封装好的网络请求函数getCourse()为异步计算函数。
builder:
(BuildContext context, AsyncSnapshot<CommonModel> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return new Text('Input a URL to start');
case ConnectionState.waiting:
return new Center(child: new CircularProgressIndicator());
case ConnectionState.active:
return new Text('');
case ConnectionState.done:
if (snapshot.hasError) {
return new Text(
'${snapshot.error}',
style: TextStyle(color: Colors.red),
);
} else {
return Text(${snapshot.data.courese_name}$);
}
}
}),
),
);
}

State生命周期

​ State是构造StatefulWidget必不可少的组件。State的生命周期主要包括三个阶段:创建、更新、销毁。

  • 创建

    State Widget的创建流程为:

    1. 构造方法,接受父组件的数据,并调用createState
    2. initState。在这个函数中可以对State中的状态值进行初始化。
    3. didChangeDependencies 。在initState后被调用,可以用来处理 State 对象依赖关系的变化
    4. build。完成以上的函数后,在build方法中,将根据父 Widget 传递过来的初始化配置数据及 State 的当前状态,创建一个 Widget 然后返回。
  • 更新

    State Widget的状态更新可以通过三种途径:setState、didChangeDependencies 或 didUpdateWidget 触发。

    • setState。当状态值发生改变的时候,可以通过调用setState方法通知flutter对Widget进行重绘(build)。
    • didChangeDependencies。当State依赖的数据发生改变时,Flutter 会回调该方法,随后触发组件构建。
    • didUpdateWidget。Widget 的配置发生变化时,或热重载时,系统会回调该方法。
  • 销毁

    当 State 被永久地从视图树中移除时,Flutter 会调用 dispose 方法,而一旦 dispose 方法被调用,组件就要被销毁了,因此可以在 dispose 方法中进行最终的资源释放、移除监听、清理环境等工作

State生命周期可以用一下图来描述:

一些组件的应用

在出现弹窗时禁用实体返回键

​ 典型场景:在进行网络请求过程中,我们不希望用户在中途进行其他操作。此时,我们可以使用一个过渡动画来提示用户目前正在进行网络调用。

​ 过渡动画的实现方法有很多,最常见的是进行弹窗提醒。所以我们需要维持网络请求过程中UI始终为弹窗页。即要求:

  1. 点击对话框以外的区域不隐藏弹窗——barrierDismissible属性
  2. 点击实体返回键不隐藏弹窗——在原有弹窗组件中外包裹一层WillPopScope,并设置onWillPop属性为false。

举例:

showDialog(
barrierDismissible: false,//barrierDismissible属性,控制点击对话框以外的区域是否隐藏对话框,为flase时不隐藏
context: context
builder: (context) {
return WillPopScope(//在原有的弹窗Wigdet外,嵌套WillPopScope,并设置onWillPop的返回值为false
child: Center(
Text('加载中'),
),
onWillPop: () {
return new Future.value(false);
},
);
});

点击空白处回收键盘

​ 在与键盘有交互的页面,用户常常进行的一个操作是点击空白处回收键盘。实现这一功能的也很简单,只需要在页面的最外层包裹一层GestureDetector,并在onTap时取消键盘焦点。

GestureDetector用于用户交互,进行基本的手势控制,其基本属性如下所示。

GestureDetector({
Key key,
this.child,
this.onTapDown,//可能导致点击的指针已联系到屏幕的特定位置
this.onTapUp,//触发点的指针已停止在特定位置与屏幕联系
this.onTap,//发生了点击。
this.onTapCancel,//触发onTapDown的指针取消触发
this.onDoubleTap,//双击
this.onLongPress,//长按
this.onLongPressUp,//长按结束
this.onVerticalDragDown,//
this.onVerticalDragStart,//指针已经接触到屏幕,而且可能开始垂直移动。
this.onVerticalDragUpdate,//与屏幕接触并垂直移动的指针沿垂直方向移动
this.onVerticalDragEnd,//以前与屏幕接触并垂直移动的指针不再与屏幕接触,并且当其停止接触屏幕时以特定速度移动。
this.onVerticalDragCancel,//
this.onHorizontalDragDown,//
this.onHorizontalDragStart,//
this.onHorizontalDragUpdate,//
this.onHorizontalDragEnd,//
this.onHorizontalDragCancel,//
// onPan可以取代onVerticalDrag或者onHorizontalDrag,三者不能并存
this.onPanDown,//指针已经接触屏幕并开始移动
this.onPanStart,//与屏幕接触并移动的指针再次移动
this.onPanUpdate,//先前与屏幕接触并移动的指针不再与屏幕接触,并且当它停止接触屏幕时以特定速度移动
this.onPanEnd,//先前触发 onPanDown 的指针未完成
this.onPanCancel,//
// onScale可以取代onVerticalDrag或者onHorizontalDrag,三者不能并存,不能与onPan并存
this.onScaleStart,//
this.onScaleUpdate,//
this.onScaleEnd,//
this.behavior,
this.excludeFromSemantics = false
})

实例:

class _CourseCommentWritePage extends State<CourseCommentWritePage> {
TextEditingController commentController = new TextEditingController();
FocusNode commentNode = new FocusNode(); Widget build(BuildContext context) {
print("build_write");
return Scaffold(
appBar: AppBar(
title: Text("标题"),
),
body: GestureDetector(
onTap: () {
commentNode.unfocus();//取消键盘焦点
},
child:Container(
decoration: BoxDecoration(
border: new Border.all(width: 2.0, color: Colors.black12),
borderRadius: new BorderRadius.all(new Radius.circular(10.0)),
),
child: TextField(
enabled: _enable,
maxLines: 12,
focusNode: commentNode,
controller: commentController,
decoration: InputDecoration(
hintText: '请输入你对课程的评价',
border: InputBorder.none,
),
),
),
)
}

在弹出键盘时,防止页面溢出

在我们实际的项目开发中,经常会遇到页面UI内容过多,导致手机一屏展示不完的情况出现,在Flutter中我们通常使用SingleChildScrollView处理滑动,即使用SingleChildScrollView组件将普通组件包裹。

同样,可以使用SingleChildScrollView中将表单TextFiled包裹,以防止溢出键盘弹出导致的溢出。

SingleChildScrollView组件:

const SingleChildScrollView({
Key key,//滚动方向,默认是垂直方向
this.scrollDirection = Axis.vertical,//是否按照阅读方向相反的方向滑动
this.reverse = false,//内容边距
this.padding,//是否使用widget树中默认的PrimaryScrollController
bool primary,//此属性接受一个ScrollPhysics类型的对象,它决定可以滚动如何响应用户操作,比如用户滑动完抬起手指后,继续执行动画,或者滑动到边界时,如何显示。
this.controller,
this.child,
})

在特定条件下禁用RaiseButton

​ RaiseButton是一个按钮组件,其一些属性作用如下:

const RaisedButton({
Key key,
@required VoidCallback onPressed,//被点击时的回调函数
ValueChanged<bool> onHighlightChanged,//水波纹高亮变化回调,按下返回true,抬起返回false
ButtonTextTheme textTheme,//按钮的主题
Color textColor,//文字的颜色
Color disabledTextColor,//按钮禁用时候文字的颜色
Color color,//按钮的背景颜色
Color disabledColor,//按钮被禁用的时候显示的颜色
Color highlightColor,//点击或者toch控件高亮的时候显示在控件上面,水波纹下面的颜色
Color splashColor,//水波纹的颜色
Brightness colorBrightness,//按钮主题高亮
double elevation,//按钮下面的阴影
double highlightElevation,//高亮时候的阴影
double disabledElevation,//按下的时候的阴影
EdgeInsetsGeometry padding,
ShapeBorder shape,//设置形状
Clip clipBehavior = Clip.none,
MaterialTapTargetSize materialTapTargetSize,
Duration animationDuration,
Widget child,
})

disabledColor字段用于设置按钮被禁用时显示的颜色。但是可以发现其实并没有将按钮设为禁用的字段。查找资料发现,当onpress()的返回值为null时,按钮自动被设为禁用。

例如:

class MyPage extennds StatelessWidget(){
bool _enable = true;
Widget build(BuildContext context){
return RaisedButton(
child: Text("修改"),
color: Colors.lightBlue,
disabledColor: Colors.grey,
onPressed:
_enable ? () => setTextEnable() :null,//当_enable为false时,禁用按钮
),
}
void setTextEnable() {
setState(() {
_enable = !_enable;
});
}
} //值得注意的是,不能将onpress的回调函数写为以下形式,写成这样并不能在当_enable为false时,禁用按钮
onpress:() {
if(_enable){
setTextEnable()
}else{
return null;
}
}

【技术博客】Flutter—使用网络请求的页面搭建流程、State生命周期、一些组件的应用的更多相关文章

  1. 搭建自己的技术博客系列(一)使用 hexo 搭建一个精美的静态博客

    1.安装 Git 和 nodejs https://hexo.io/zh-cn/docs/

  2. 技术人如何利用 github+Jekyll ,搭建一个独立免费的技术博客

    上次有人留言说,技术博客是程序员的标配,但据我所知绝大部分技术同学到现在仍然没有自己的技术博客.原因有很多,有的是懒的写,有的是怕写不好,还有的是一直想憋个大招,幻想做到完美再发出来,结果一直胎死腹中 ...

  3. 【新版】Android技术博客精华汇总

    [新版]Android技术博客精华汇总(原文链接内持续更新) http://www.apkbus.com/thread-313856-1-1.html Kotlin Kotlin学习资料汇总 http ...

  4. 一文搞定scrapy爬取众多知名技术博客文章保存到本地数据库,包含:cnblog、csdn、51cto、itpub、jobbole、oschina等

    本文旨在通过爬取一系列博客网站技术文章的实践,介绍一下scrapy这个python语言中强大的整站爬虫框架的使用.各位童鞋可不要用来干坏事哦,这些技术博客平台也是为了让我们大家更方便的交流.学习.提高 ...

  5. [技术博客] BeautifulSoup4分析网页

    [技术博客] BeautifulSoup4分析网页 使用BeautifulSoup4进行网页文本分析 前言 进行网络爬虫时我们需要从网页源代码中提取自己所需要的信息,分析整理后存入数据库中. 在pyt ...

  6. 如何写出高质量的技术博客 这边文章出自http://www.jianshu.com/p/ae9ab21a5730 觉得不错直接拿过来了 好东西要大家分享嘛

        如何写出高质量的技术博客?答案是:如果你想,就一定能写出高质量的技术博客.看起来很唯心,但这就是事实.有足够愿力去做一件目标明确,有良好反馈系统的事情往往很简单.就是不停地训练,慢慢地,你自己 ...

  7. 【转】【技术博客】Spark性能优化指南——高级篇

    http://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&mid=2651745207&idx=1&sn=3d70d59cede236e ...

  8. [转]有哪些值得关注的技术博客(Java篇)

    有哪些值得关注的技术博客(Java篇)   大部分程序员在自学的道路上不知道走了多少坑,这个视频那个网站搞得自己晕头转向.对我个人来说我平常在学习的过程中喜欢看一些教程式的博客.这些博客的特点: 1. ...

  9. 最值得收藏的java技术博客(Java篇)

    第一个:java_my_life 作者介绍:找不到原作者信息.大概做了翻阅全部是2012年的博客. 博客主要内容:主要内容是关于Java设计模式的一些讲解和学习笔记,在相信对学习设计模式的同学帮助很大 ...

随机推荐

  1. ELK学习之Logstash+Kafka篇

    上一篇介绍了一下Logstash的数据处理过程以及一些基本的配置功能,同时也提到了Logstash作为一个数据采集端,支持对接多种输入数据源,其中就包括Kafka.那么这次的学习不妨研究一下Logst ...

  2. Linux内核中的Workqueue机制分析

    1. 什么是workqueue Linux中的workqueue(工作队列)主要是为了简化在内核创建线程而设计的.通过相应的工作队列接口,可以使开发人员只关心与特定功能相关的处理流程,而不必关心内核线 ...

  3. QT之静态函数发送信号

    一.简介 由于博主本人是初学者对QT的机制不了解,所以遇到了一个比较大的坑,特此记录一下.我遇到的问题是无法在静态函数中向另外一个类发送信号.解决办法:先将信号发送给同类中的普通函数,然后在从普通函数 ...

  4. .net中使用JSON

    在.NET使用JSON作为数据交换格式 ASP.NET中JSON的序列化和反序列化 三种方式: 使用System.Web.Script.Serialization.JavaScriptSerializ ...

  5. python库--tensorflow--可视化

    方法 返回值类型 参数 说明 tf.summary .FileWrite()   创建事件文件     logdir 文件保存路径(C盘), 通过tensorboard --logdir=文件路径(l ...

  6. Vue+elementUI 创建“回到顶部”组件

    1.创建"回到顶部"组件 1 <template> 2 <transition name="el-fade-in"> 3 <div ...

  7. uni-app仿抖音APP短视频+直播+聊天实例|uniapp全屏滑动小视频+直播

    基于uniapp+uView-ui跨端H5+小程序+APP短视频|直播项目uni-ttLive. uni-ttLive一款全新基于uni-app技术开发的仿制抖音/快手短视频直播项目.支持全屏丝滑般上 ...

  8. nginx proxy_next_upstream 与openresty balancer.set_more_tries的使用

    背景 我们这边网关服务使用的 kong,前段时间上线一个服务,这个服务它报错了,产生了502的错误码,追查这个报错的时候发现了网关服务的两个可疑的地方,第一个疑点是我们在Kong上配置的 Retrie ...

  9. leetcode 盛水最多的容器 解析

    采用双指针法: 主要思想:定义头尾两个指针,分别向中间遍历,当相遇时结束循环.存储每一次遍历容器盛水的最大容量,并不断更新. 盛水的最大容量为 左右指针高度的最小值 乘以 左右指针的距离即宽度. 则可 ...

  10. jQuery <= 1.11.3 DomXSS漏洞

    听团里说WordPress又爆跨站漏洞了:" XSS漏洞在Jetpack和二十五默认主题影响百万WordPress用户 ",分析发现原来是jQuery老版本的DOM XSS漏洞[错 ...