我有一个有趣的设置。
我有一个扩展State
并提供一些额外功能的类。在此类中,我有一个isLoading
变量,该变量使我可以在此状态的任何实例中显示一个CircularProgressIndicator
。
我有一个类,该类向服务器执行API请求以获取数据,同时它使用控制器类在任何适用的小部件中将isLoading
设置为true,以表明它正在加载数据。
问题是,当我加载新页面,然后API处理程序更新isLoading
参数并且ConvenienceState
类运行setState()
时,我得到了现在隐藏的错误页,但我不确定为什么会这样。当前路线后面的页面是否必须以不方便的方式进行重建?我该如何解决这个问题?
这是一个有效的错误示例:
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Bug example',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Bug Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
State<StatefulWidget> createState() {
return MyHomePageState();
}
}
class MyHomePageState extends ConvenienceState<MyHomePage> {
MyHomePageState(){
API.getData();
}
// It doesn't work when API.getData() is here instead, either
// @override
// void initState() {
// super.initState();
// API.getData();
// }
@override
Widget buildContent(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Center(
child: RaisedButton(
onPressed: (){
Navigator.of(context).push(
MaterialPageRoute(
builder: (context){
return NextPage();
}
)
);
},
child: Text("Next Page"),
),
),
),
);
}
}
class NextPage extends StatefulWidget{
@override
State<StatefulWidget> createState() {
return NextPageState();
}
}
class NextPageState extends ConvenienceState<NextPage>{
NextPageState(){
API.getData();
}
// It doesn't work when API.getData() is here instead, either
// @override
// void initState() {
// super.initState();
// API.getData();
// }
@override
Widget buildContent(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("NextPage"),),
body: Center(child: Text("Content"),),
);
}
}
class API {
static Future<bool> getData()async{
RemoteController.update("loading");
return await Future<bool>.delayed(Duration(seconds: 3),(){
RemoteController.update("notLoading");
return true;
});
}
}
class RemoteController {
static List<Function(String)> listeners = [];
static void update(String type) {
listeners.forEach((Function listener) {
listener(type);
});
}
static void addListener(Function(String) listener) {
listeners.add(listener);
}
static void removeListener(Function(String) listener) {
listeners.remove(listener);
}
}
abstract class ConvenienceState<T extends StatefulWidget> extends State{
T get widget {
return super.widget;
}
/// Keeps track of whether or not the page is built (ready for [setState()])
bool isBuilt = false;
bool _isLoading = false;
/// Determines if the loading screen is displayed
set isLoading(bool value){
_isLoading = value;
if(mounted && isBuilt)
setState(() {});
}
/// Determines if the loading screen is displayed
get isLoading{
return _isLoading;
}
@override
initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
isBuilt = true;
});
RemoteController.addListener(rcListener);
}
void rcListener(String type) {
if(type=="loading"){
isLoading = true;
}
if(type=="notLoading"){
isLoading = false;
}
}
@override
dispose(){
RemoteController.removeListener(rcListener);
super.dispose();
}
Widget buildContent(BuildContext context);
@override
build(BuildContext context){
return Stack(
children: <Widget>[
buildContent(context),
Visibility(
visible: isLoading,
child: Center(child: CircularProgressIndicator()),
),
],
);
}
}
当您单击“ NextPage”按钮时,将显示错误,涉及到MyHomePage
类。