https://github.com/flutter/flutter/issues/18828

https://blog.csdn.net/u011272795/article/details/83010974  <<<<<<<===============

https://medium.com/saugo360/flutter-my-futurebuilder-keeps-firing-6e774830bc2

Flutter: My FutureBuilder Keeps Firing!

 
Aug 19, 2018

If you’ve ever done any serious Flutter development, then you have definitely faced the problem in the title above. But don’t worry, You’re not alone!

What is the problem?

The FutureBuilder widget that Flutter provides us to create widgets based on the state of some future, keeps re-firing that future every time a rebuild happens! The problem is best manifested with this simple example:

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen()
);
}
} class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
} class _HomeScreenState extends State<HomeScreen> { bool _switchValue; @override
void initState() {
super.initState();
this._switchValue = false;
} @override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Switch(
value: this._switchValue,
onChanged: (newValue) {
setState(() {
this._switchValue = newValue;
});
},
),
FutureBuilder(
future: this._fetchData(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator()
);
default:
return Center(
child: Text(snapshot.data)
);
}
}
),
],
),
);
} _fetchData() async {
await Future.delayed(Duration(seconds: 2));
return 'REMOTE DATA';
}
}
  • Our app displays aHomeScreen on which we have one Switch widget and one FutureBuilder that loads remote data and displays it on the screen.
  • The FutureBuilder subscribes to the future returned from the function _fetchData. This function simulates a server that returns its result after two seconds.
  • When the user taps the switch, we update the member _switchValue, which is then fed into the switch itself, to change its actual value.

If you run this app, the following happens:

 

Flipping the switch affects the state of the FutureBuilder

Even though the switch and the FutureBuilder are not related in any form, every time we change the switch value (by calling setState), the FutureBuilder goes through its whole life-cycle again! It re-fetches the future, causing unneeded traffic, and shows the loading again, causing bad user experience.

This problem manifests itself in a variety of ways. In some cases it’s not even as obvious as the example above. For example:

  • Network traffic being generated from pages that are not currently on screen
  • Hot reloading not working properly
  • Losing the Navigator state when updating values in some Inherited Widgets
  • etc…

But what is the cause of all of this? And how can we solve it?

The didUpdateWidget problem

Note: In this section I will take a closer look at how FutureBuilder works. If you’re not interested in this, you can skip to the solution.

If we take a closer look at the code of FutureBuilder, we find that it is a StatefulWidget. As we know, StatefulWidgets maintain a long-livedStateobject. This state has a few methods that manage its life-cycle, like initStatebuild, and didUpdateWidgetinitState is called only once when the state object is first created, and build is called every time we need to build the widget to display, but what what about didUpdateWidget? This method is called whenever the widget attached to this State object changes. When the widget is rebuilt with new inputs, the old widget is disposed, and a new widget is created and assigned to the State object, and didUpdateWidget is called to do anything we want to do before the rebuild. In case of FutureBuilder, this method looks like this:

@override
void didUpdateWidget(FutureBuilder<T> oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.future != widget.future) {
if (_activeCallbackIdentity != null) {
_unsubscribe();
_snapshot = _snapshot.inState(ConnectionState.none);
}
_subscribe();
}
}

It’s basically saying: if, when rebuilt, the new widget has a different Future instance than the old one, then repeat everything: unsubscribe, and subscribe again.

Well, that’s the key! If we provide it with the same future, then it will not refire!

But aren’t we providing the same future? we’re calling the same function! well, it’s not the same future instance. Our function is doing exactly the same work, but then returning a new future, different from the old one.

So, what we want to do is to store or cache the output of the function the first time it is called, and then provide this same output whenever the function is called again. This process is known as memoization.

Solution: Memoize the future

Memoization is, in simple terms, caching the return value of a function, and reusing it when that function is called again. Memoization is mostly used in functional languages, where functions are deterministic (they always return the same output for the same inputs), but we can use simple memoization for our problem here, to make sure the FutureBuilder always receives the same future instance.

To do that, we will use Dart’s AsyncMemoizer. This memoizer does exactly what we want! It takes an asynchronous function, calls it the first time it is called, and caches its result. For all subsequent calls to the function, the memoizer returns the same previously calculated future.

Thus, to solve our problem, we start by creating an instance of AsyncMemoizerin our widget:

final AsyncMemoizer _memoizer = AsyncMemoizer();

Note: you shouldn’t instantiate the memoizer inside a StatelessWidget, because Flutter disposes of StatelessWidgets at every rebuild, which basically beats the purpose. You should instantiate it either in a StatefulWidget, or somewhere where it can persist.

Afterwards, we will modify our _fetchData function to use that memoizer:

_fetchData() {
return this._memoizer.runOnce(() async {
await Future.delayed(Duration(seconds: 2));
return 'REMOTE DATA';
});
}
  • We wrapped our function with AsyncMemoizer.runOnce which does exactly what it sounds like; it runs the function only once, and when called again, returns the cached future.

And that’s it! Our FutureBuilder now only fires the first time around:

 

Thus, our FutureBuilder was getting confused, and thinking that a new future was passed to it, causing it to refire every time. To solve this, we used Dart’s AsyncMemoizer to pass the same future instance every time.

I hope this has been helpful! Let me know what you think!

textfield reload issue and other things reload problem.===================================的更多相关文章

  1. eclipse 打开是报错"reload maven project has encountered a problem"

    不需要删除整个 .metadata 如果删除这个代价是重新导入全部项目 D:\eclipse-workspace\.metadata\.plugins\org.eclipse.e4.workbench ...

  2. 在IE浏览器中执行OpenFlashChart的reload方法时无法刷新的解决方法

    由于项目需求,需要在网页上利用图表展示相关数据的统计信息,采用了OpenFlashChart技术.OpenFlashChart是一款开源的以Flash和Javascript为技术基础的免费图表,用它能 ...

  3. javascript 中的location.reload

    location.reload()是什么意思 location.reload() 括号内有一个参数 true/false , 为空和false的效果一样. 如果该方法没有规定参数,或者参数是 fals ...

  4. 把Nginx加入系统服务 service nginx (start | stop | restart | reload)

    vim /etc/init.d/nginx 1 #!/bin/bash  2 # nginx Startup script for the Nginx HTTP Server  3 # it is v ...

  5. 使用Tomcat的Reload提高开发速度(翻译)

    欢迎转载http://www.cnblogs.com/coodream2009,有翻译的不太准确的地方请大家指出,我继续修改完善. 按照Java Servlet规范第四部分推荐的,Tomcat系统的实 ...

  6. layui table数据表格reload where参数保留问题

    layui table数据表格reload where参数保留问题 在使用layui过程中多多少少会遇到些问题 table reload 有个坑:reload时where参数会保留上次的参数,如果用 ...

  7. javascript:location.reload()和location.replace()的区别,及对图片缓存的影响。

    有段时间没有清理IE的临时文件(缓存文件),在我清理的时候,我突然发现一个问题. 我打开的一个网站,图片默认缓存一个月的,但我发现,当我上传图片或删除图片之后,图片重新缓存,也就意味着,在我上传新图片 ...

  8. Python中的reload函数

    Python中的import语句可以导入module文件,但是import语句只是第一次导入的时候会执行module文件中的代码,然后就会把导入的模块文件存入到内存,当再次导入的时候,Python是直 ...

  9. python之reload用法

    一.python2和python3的区别 python2中可以直接使用reload().python3中需要从库中导入,有两种方法: >>> from imp import relo ...

随机推荐

  1. 【C++】子序列匹配问题

    /* 一个串的“子序列”(subsequence)是将这个串中的一些字符提取出来得到一个新串,并且不改变它们的相对位置关系.例如,串"XDoi","XianYu!&quo ...

  2. vue 实现子向父传值

    父组件 <template> <div id="app"> <child @onChange='onChildValue'></child ...

  3. 汇编-10.0-CALL和RET指令

    call和ret指令都是转移指令,他们都是修改IP,或同时修改CS和IP.它们常被共同用来实现子程序设计. 1.ret和retf ret指令用栈中的数据,修改IP的内容,从而实现近转移: retf指令 ...

  4. 马拉车算法,mannacher查找最长回文子串

    作用: 在线性时间内找到一个字符串的最大回文子串 原理: 奇偶变换:为处理字符串方便,现将给定的任意字符串进行处理,使所有可能的奇数/偶数长度的回文子串都转换成了奇数长度. 具体就是在每个字符的两边都 ...

  5. Java面试题和解答(一)

    1.说说JVM原理?内存泄露与溢出区别,何时产生内存泄露? JVM原理 :http://www.cnblogs.com/jiayi/archive/2010/06/08/1753863.html 内存 ...

  6. CentOS7安装vsftpd3.0.2、以及虚拟用户配置

    vsftpd(very secure ftp daemon)是一款运行在Linux操作系统上的FTP服务程序,不仅完全开源而且免费,还具有很高的安全性.传输速度,以及支持虚拟用户验证. vsftpd ...

  7. U盘制作系统盘的方法:

    1, 使用 u 盘制作 ubuntu16.04 的方法, 安装软件后,直接使用软件将 U盘制作成系统盘就好了 [1] 下载安装工具: UltraISO  官网:  http://www.ezbsyst ...

  8. Centos7安装jexus,部署asp.net core,asp.net mvc

    什么是Jexus 官网解释:https://www.jexus.org/ Jexus是一款Linux平台上的高性能WEB服务器和负载均衡网关,Jexus Web Service,简称JWS,以支持AS ...

  9. 华为AR-111S路由器GRE协议设置

    一.GRE的定义: gre(generic routing encapsulation,通用路由封装)协议是对某些网络层协议(如ip 和ipx)的数据报进行封装,使这些被封装的数据报能够在另一个网络层 ...

  10. mysql添加用户,授权,刷新权限

    创建用户 CREATE USER 'test'@'localhost' IDENTIFIED BY '123456'; 赋权 GRANT ALL PRIVILEGES ON *.* TO 'test' ...