实际使用情况: - 在初始化过程中,应用程序检测到没有网络连接。缺乏网络连接可能会阻止正确启动(例如,加载外部资源,如JSON文件...)。 - 在初始握手期间,需要下载某些重要资源的新版本(更新类型)。
在这两种情况下,我希望应用程序进行完全重启,而不必在ApplicationState级别构建复杂的逻辑。
您可以将整个应用程序包装在一个StatefulWidget中。当您想要重新启动应用程序时,使用具有不同Key
的子元素重建该StatefulWidget。
这将使您失去整个应用程序的状态。
import 'package:flutter/material.dart';
void main() {
runApp(
RestartWidget(
child: MaterialApp(),
),
);
}
class RestartWidget extends StatefulWidget {
RestartWidget({this.child});
final Widget child;
static void restartApp(BuildContext context) {
context.findAncestorStateOfType<_RestartWidgetState>().restartApp();
}
@override
_RestartWidgetState createState() => _RestartWidgetState();
}
class _RestartWidgetState extends State<RestartWidget> {
Key key = UniqueKey();
void restartApp() {
setState(() {
key = UniqueKey();
});
}
@override
Widget build(BuildContext context) {
return KeyedSubtree(
key: key,
child: widget.child,
);
}
}
在这个例子中,您可以使用RestartWidget.restartApp(context)
从任何地方重置您的应用程序。
flutter_phoenix package基于Rémi Rousselet的答案,让其更加简单易用。
void main() {
runApp(
Phoenix(
child: App(),
),
);
}
然后,当你需要重新启动应用时,只需调用:
Phoenix.rebirth(context);
关于@Remi的答案,我想补充一点。该答案在大多数情况下重启应用程序非常有效。但是,如果你经常进行导航路由并到达一个状态,会出现以下错误:
The method 'restartApp' was called on null
。
要解决此错误,您需要知道上下文并多次使用Navigator.of(context).pop();
返回。对我来说,解决方法是回到初始路由。这将注入所有新状态。在需要重新启动的位置,只需添加此行。
Navigator.pushNamedAndRemoveUntil(context,'/',(_) => false);
dependencies:
flutter_restart: ^0.0.3
使用方法:
void _restartApp() async {
FlutterRestart.restartApp();
}
你也可以使用runApp(new MyWidget)函数来实现类似的功能。
这个函数的作用是:
将给定的widget填充并附加到屏幕上。
在布局期间,该widget被赋予了约束条件,强制它填满整个屏幕。如果您希望将widget对齐到屏幕的一侧(例如顶部),请考虑使用Align widget。如果您希望将widget居中,您也可以使用Center widget。
再次调用runApp会将先前的根widget从屏幕上分离,并在其位置附加给定的widget。新的widget tree与先前的widget tree进行比较,并将任何差异应用于底层渲染树,类似于StatefulWidget在调用State.setState后重新构建时发生的情况。
runApp
的小部件中指定了一个UniqueKey
,那应该是可以的。更糟糕的是,它会让需要刷新的小部件了解得太多。 - Rémi Rousselet从技术角度来说,这并不是一次真正的重启,但它适用于大多数情况:
// Remove any route in the stack
Navigator.of(context).popUntil((route) => false);
// Add the first route. Note MyApp() would be your first widget to the app.
Navigator.push(
context,
CupertinoPageRoute(builder: (context) => const MyApp()),
);
我想在注销后重新启动我的应用程序。 所以我使用了https://pub.dev/packages/flutter_phoenix (flutter phoenix)。 这对我很有帮助。
$ flutter pub add flutter_phoenix
runApp(
Phoenix(
child: MyApp()
));
Phoenix.rebirth(context)
注意: flutter_phoenix 不能在操作系统级别上重新启动应用程序,它只能在应用程序级别上重新启动。
我尝试了上面建议的方法,但都没有起作用,而且我正在使用getx。 所以最终我修改了被接受的答案并加入了延迟作为解决方法,现在它可以工作了。
class RestartAppWidget extends StatefulWidget {
RestartAppWidget({this.child});
final Widget child;
static void restartApp(BuildContext context) {
context.findAncestorStateOfType<_RestartAppWidgetState>().restartApp();
}
@override
_RestartAppWidgetState createState() => _RestartAppWidgetState();
}
class _RestartAppWidgetState extends State<RestartAppWidget> {
bool restarting = false;
void restartApp() async {
restarting = true; // restart variable is set to true
setState(() {});
Future.delayed(Duration(milliseconds: 300)).then((value) {
setState(() {
restarting = false; //restart variable is set to false
});
});
// setState(() {
// key = UniqueKey();
// });
}
@override
Widget build(BuildContext context) {
if (restarting) {
return SizedBox(); //an empty Sizedbox is displayed for 300 milliseconds you can add a loader if you want
}
return SizedBox(
child: widget.child,
);
}
}`
runApp(RestartAppWidget(
child: MyApp(),
))
你可以使用这段代码在Flutter层面重新启动应用
RestartAppWidget.restartApp(Get.context);
final _RestartWidgetState state = context.findAncestorStateOfType<State<RestartWidget>>();
,基于[https://dev59.com/FlIH5IYBdhLWcg3weukq]。 - Richard Johnson