博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Flutter实战4 -- 天气查询APP重构之状态管理(InheritedWidget)
阅读量:6926 次
发布时间:2019-06-27

本文共 4885 字,大约阅读时间需要 16 分钟。

0x00 前言

前面三篇文章:

写了一个很简单的应用,在将这个APP的功能复杂化之前,我们必须要选择一个合适的框架,这样才能避免代码失控,就是随着APP功能的增加,代码的结构和管理越来越复杂。本篇文章将如何使用InheritedWidget来管理状态。

0x01 代码

本篇文章所涉及的代码:

分支:InheritedWidget

0x02 InheritedWidget简介

InheritedWidget用于在树中传递信息

  • 为何InheritedWidget可以用于传递信息?

因为InheritedWidget的实现是对象池,所有InheritedWidget的实例都在这个的对象池里,想要的时候从这个对象池里去取,所以可以在树中的任何位置都拿到InheritedWidget的单例对象,所以可以做到在树中传递信息。

0x03 InheritedWidget源码解析

上面说的对象池,在InheritedWidget中是一个数组,如下:

Map
_inheritedWidgets;复制代码

是一个Map,把类型Type作为key,具体实例作为value,所以0x06讲的在子节点获取InheritedWidget,你就知道为何要传Type了

假设一个子节点InheritedWidget的实例,持有_inheritedWidgets数组,这个数组的值,首先是把这个InheritedWidget父节点的_inheritedWidgets值赋值给子节点,然后子节点在把自己的实例添加到这个数组,所以你也就可以明白0x04讲的作用域,为啥InheritedWidget的作用域是自己及自己的子节点了。

0x04 InheritedWidget功能

InheritedWidget继承自ProxyWidget,ProxyWidget继承自Widget,可以单独使用,但是没有状态,为了有状态,一般和StatefulWidget搭配使用,搭配方法的示例如下: 需要有三个类:

  1. AppStateWidget(继承StatefulWidget)
  2. AppState (创建InheritedWidget,AppState持有数据及业务逻辑)
  3. InheritedWidget(持有AppState)

0x05 InheritedWidget的作用域

InheritedWidget的作用域只能包括自己及自己的子节点,所以InheritedWidget在树中只能向下传递,所以在天气查询的APP中,为了让InheritedWidget的作用域是全局的,得这么做:

要覆盖Material App 的根节点。

void main(){  runApp(WeatherControllerWidget(child: MyApp()));}复制代码

0x06 子节点获取InheritedWidget的方法

使用 context.inheritFromWidgetOfExactType(Type targetType)这个方法 将你想要获取的InheritedWidget的类型作为参数传进去

因为这个会经常用到,为了可读性,一般会在自己的InheritedWidget里添加of方法,包装成如下使用:

static WeatherControllerState of(BuildContext context){    return (context.inheritFromWidgetOfExactType(_WeatherInheritedWidget) as _WeatherInheritedWidget).state;  }复制代码

0x07 天气查询APP重构

接下来我们要写一个状态管理的类,这个类持有天气查询APP里所有的数据,以及实现数据请求的功能。代码如下:

import 'dart:convert';import 'package:flutter/widgets.dart';import 'package:gdg_weather/page/city/CityData.dart';import 'package:gdg_weather/page/weather/WeatherData.dart';import 'package:http/http.dart' as http;//StatefulWidget 和 InheritedWidget配合使用class WeatherControllerWidget extends StatefulWidget{  Widget child;  //这里需要传入child,这个参数,InheritedWidget初始化的时候需要用到  WeatherControllerWidget({this.child});    //这里和其他StatefulWidget一样,返回一个state  @override  State
createState() { // TODO: implement createState return WeatherControllerState(); } //这里提供了一个static方法,是为了外面好获取 static WeatherControllerState of(BuildContext context){ return (context.inheritFromWidgetOfExactType(_WeatherInheritedWidget) as _WeatherInheritedWidget).state; }}//这个类是核心,用于状态管理,持有数据,并且功能都在这里实现class WeatherControllerState extends State
{ //持有的数据 List
cityList = new List
(); String curCityName; WeatherData weather = WeatherData.empty(); //获取城市列表的方法 void getCityList() async { final response = await http.get('https://search.heweather.net/top?group=cn&key=ebb698e9bb6844199e6fd23cbb9a77c5'); List
list = new List
(); if(response.statusCode == 200){ //解析数据 Map
result = json.decode(response.body); for(dynamic data in result['HeWeather6'][0]['basic']){ CityData cityData = CityData(data['location']); list.add(cityData); } } setState(() { cityList = list; }); } //获取当前城市的实时天气 void getCityWeather() async{ final response = await http.get('https://free-api.heweather.com/s6/weather/now?location='+curCityName+'&key=ebb698e9bb6844199e6fd23cbb9a77c5'); if(response.statusCode == 200){ setState(() { weather = WeatherData.fromJson(json.decode(response.body)); }); }else{ setState(() { weather = WeatherData.empty(); }); } } //表示选择了哪个城市 void selectCity(String city){ curCityName = city; } //这里返回了_WeatherInheritedWidget @override Widget build(BuildContext context) { // TODO: implement build return _WeatherInheritedWidget( state: this, child: widget.child, ); }}//_WeatherInheritedWidgetclass _WeatherInheritedWidget extends InheritedWidget{ WeatherControllerState state; _WeatherInheritedWidget({ Key key, @required this.state, @required Widget child }):super(key: key,child: child); @override bool updateShouldNotify(InheritedWidget oldWidget) { // TODO: implement updateShouldNotify return true; }}复制代码

0x08 传递数据

获取WeatherState的方法:

final weatherState = WeatherControllerWidget.of(context);复制代码

具体例子如下:

class CityState extends State
{ CityState(){ } @override Widget build(BuildContext context) { // TODO: implement build final weatherState = WeatherControllerWidget.of(context); weatherState.getCityList(); return ListView.builder( itemCount: weatherState.cityList.length, itemBuilder: (context,index){ return ListTile( title: GestureDetector( child: Text(weatherState.cityList[index].cityName), onTap:(){ weatherState.selectCity(weatherState.cityList[index].cityName); Navigator.push( context, MaterialPageRoute(builder: (context) => WeatherWidget()) ); }, ), ); }); }}复制代码

转载地址:http://wkujl.baihongyu.com/

你可能感兴趣的文章
大数据技术创新呈现“原创-开源-产品化”的阶梯格局
查看>>
spark combineByKey
查看>>
NMath矩阵分解的两种方式
查看>>
启动AVD时log提示“emulator-X disconnected! Cancelling 'X activity launch'!”
查看>>
10个最新手机美食APP界面设计欣赏
查看>>
SQL查找重复行
查看>>
关于加密、签名及证书
查看>>
Android之service探究
查看>>
ASP.NET下Word文档的在线编辑、保存和全文关键字搜索的完整示例
查看>>
SYBASE存储过程详解
查看>>
集体智慧算法
查看>>
压缩原理及无线的一点思考
查看>>
ifcfg-p1p1
查看>>
Linux磁盘和文件系统
查看>>
LINUX iptables防火墙规则的匹配条件
查看>>
linux解决磁盘indoe满了问题
查看>>
mysql索引的类型和优缺点
查看>>
CentOS-6.5 安装教程-配置篇-网卡配置
查看>>
Java取整数
查看>>
redis的存储的5种数据类型
查看>>