【发布时间】:2019-12-06 01:15:21
【问题描述】:
这可能是由于我正在做或忘记做的一些愚蠢的事情造成的。 以下是 Flutter 的完整工作代码示例(截至 2019 年 12 月 5 日)和用于重现此问题的 HTTP 回显服务器(httpbin)。
运行httpbin:
docker run -p 1234:80 kennethreitz/httpbin
然后将代码加载到新的 Flutter 应用中。 在重新加载应用程序时,单击抽屉中的 Route A,您会在控制台中打印以下内容:
flutter: Loaded <RouteA> (Stateful)
flutter: Got data from Route A 1 times.
点击Route B,你会得到:
flutter: Loaded <RouteB> (Stateful)
flutter: Got data from Route B 1 times.
flutter: Loaded <RouteA> (Stateful)
flutter: Got data from Route A 2 times.
(它重新加载路由 A,执行另一个 HTTP 请求)。
再次加载Route B,你会得到:
flutter: Loaded <RouteB> (Stateful)
flutter: Got data from Route B 2 times.
flutter: Loaded <RouteB> (Stateful)
flutter: Loaded <RouteA> (Stateful)
flutter: Got data from Route A 3 times.
flutter: Got data from Route B 3 times.
再次加载Route B,你会得到:
flutter: Loaded <RouteB> (Stateful)
flutter: Got data from Route B 4 times.
flutter: Loaded <RouteB> (Stateful)
flutter: Loaded <RouteA> (Stateful)
flutter: Loaded <RouteB> (Stateful)
flutter: Got data from Route B 5 times.
flutter: Got data from Route B 6 times.
flutter: Got data from Route A 4 times.
这些负载中的每一个都对应一个 HTTP 请求,因此,如果应用已打开足够长的时间,它可能会为单个有状态小部件负载发出 100 个 HTTP 请求。
请注意,如果您加载 Route C(一个无状态小部件),它只会加载一次。
这显然与 StatefulWidgets 的重新加载方式有关,但我被卡住了,无法在网上找到有类似问题的帖子。
Flutter 为什么要这样做?对于 HTTP 请求,如何使其表现得像 StatelessWidget?
见下面的代码示例
/*
* Flutter code for weird HTTP behavior with StatefulWidget
*
* Make sure you're also running httpbin locally with the following command:
*
* docker run -p 1234:80 kennethreitz/httpbin
*/
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
int routeAqueries = 0;
int routeBqueries = 0;
int routeCqueries = 0;
void main() {
runApp(HttpDebug());
}
class HttpDebug extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'HomeDebug',
home: HomeDebug(),
);
}
}
class HomeDebug extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
drawer: _Drawer(),
body: Center(child: Text('Home')),
);
}
}
class RouteA extends StatefulWidget {
@override
_RouteAState createState() => _RouteAState();
}
class _RouteAState extends State<RouteA> {
@override
Widget build(BuildContext context) {
print('Loaded <RouteA> (Stateful)');
return Scaffold(
appBar: AppBar(title: Text('Route A')),
drawer: _Drawer(),
body: FutureBuilder<String>(
future: fetchRoute('routeA'),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Text('RouteA Data: ${snapshot.data}');
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('Loading');
}
},
),
);
}
}
class RouteB extends StatefulWidget {
@override
_RouteBState createState() => _RouteBState();
}
class _RouteBState extends State<RouteB> {
@override
Widget build(BuildContext context) {
print('Loaded <RouteB> (Stateful)');
return Scaffold(
appBar: AppBar(title: Text('Route B')),
drawer: _Drawer(),
body: FutureBuilder<String>(
future: fetchRoute('routeB'),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Text('RouteB Data: ${snapshot.data}');
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('Loading');
}
},
),
);
}
}
class RouteC extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('Loaded <RouteC> (Stateless)');
return Scaffold(
appBar: AppBar(title: Text('Route C')),
drawer: _Drawer(),
body: FutureBuilder<String>(
future: fetchRoute('routeC'),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Text('RouteC Data: ${snapshot.data}');
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('Loading');
}
},
),
);
}
}
class _Drawer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
children: <Widget>[
ListTile(
title: Text('Home'),
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomeDebug()),
),
),
ListTile(
title: Text('Route A'),
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => RouteA()),
),
),
ListTile(
title: Text('Route B'),
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => RouteB()),
),
),
ListTile(
title: Text('Route C'),
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => RouteC()),
),
),
],
)
);
}
}
Future<String> fetchRoute(String route) async {
Map<String, int> routes = {
'routeA': 200,
'routeB': 201,
'routeC': 202,
};
final response = await http.get('http://localhost:1234/status/${routes[route]}');
if (response.statusCode == 200) {
print('Got data from Route A ${++routeAqueries} times.');
return 'Welcome to Route A';
} else if (response.statusCode == 201) {
print('Got data from Route B ${++routeBqueries} times.');
return 'Welcome to Route B';
} else if (response.statusCode == 202) {
print('Got data from Route C ${++routeCqueries} times.');
return 'Welcome to Route C';
}
}
【问题讨论】:
标签: flutter