我不确定要查找的内容,因此随时向我提供有关查找位置的指示。我正在学习,因此非常感谢。
我刚刚发现可以在flutter中使用命名路由,并且我正尝试着使事情变得更可预测。但是,在某些时候,我的UserDataContainer有状态小部件会丢失其状态值。所以我有一些用户数据,它消失了。
这里是一些代码。
这是我的用户数据容器:
// app_state_container.dart
//import 'package:advanced_app/models/app_state.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:myapp/FoodLib/user.dart';
class UserDataContainer extends StatefulWidget {
// Your apps state is managed by the container
final UserDataType userdata = UserDataType();
// This widget is simply the root of the tree,
// so it has to have a child!
final Widget child;
UserDataContainer({@required this.child
// @required this.userdata,
}) {
print("CREATED USERDATA CONTAINER");
print("The name: " + this.userdata.name);
}
// This creates a method on the AppState that's just like 'of'
// On MediaQueries, Theme, etc
// This is the secret to accessing your AppState all over your app
static _UserDataContainerState of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(_InheritedUserDataContainer)
as _InheritedUserDataContainer)
.data;
}
@override
_UserDataContainerState createState() => new _UserDataContainerState();
}
class _UserDataContainerState extends State<UserDataContainer> {
// Just padding the state through so we don't have to
// manipulate it with widget.state.
// UserDataType userdata = UserDataType();
String name = "test";
@override
void initState() {
// You'll almost certainly want to do some logic
// in InitState of your AppStateContainer. In this example, we'll eventually
// write the methods to check the local state
// for existing users and all that.
super.initState();
}
// So the WidgetTree is actually
// AppStateContainer --> InheritedStateContainer --> The rest of your app.
@override
Widget build(BuildContext context) {
return new _InheritedUserDataContainer(
data: this,
child: widget.child,
);
}
}
// This is likely all your InheritedWidget will ever need.
class _InheritedUserDataContainer extends InheritedWidget {
// The data is whatever this widget is passing down.
final _UserDataContainerState data;
// InheritedWidgets are always just wrappers.
// So there has to be a child,
// Although Flutter just knows to build the Widget thats passed to it
// So you don't have have a build method or anything.
_InheritedUserDataContainer({
Key key,
@required this.data,
@required Widget child,
}) : super(key: key, child: child);
// This is a better way to do this, which you'll see later.
// But basically, Flutter automatically calls this method when any data
// in this widget is changed.
// You can use this method to make sure that flutter actually should
// repaint the tree, or do nothing.
// It helps with performance.
@override
bool updateShouldNotify(_InheritedUserDataContainer old){
if(
data.widget.userdata.fooditems.length !=
old.data.widget.userdata.fooditems.length){
return true;
}
// print("SAME");
return false;
}
}
UserDataType
是包含消失的数据的类。
这是我的主要应用,具有Material类:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new DynamicTheme(
defaultBrightness: Brightness.light,
data: (brightness) => new ThemeData(
primarySwatch: Colors.teal,
brightness: brightness,
),
themedWidgetBuilder: (context, theme) {
return UserDataContainer(
child: MaterialApp(
title: 'Title',
home: UserLoader(),
theme: theme,
routes: {
// When navigating to the "/" route, build the FirstScreen widget.
'/userpage': (context) => User(),
'/settings': (context) => SettingsPage(),
'/saved_stuff' : (context) => SavedRecipesPage(),
'/database' : (context) => Database(),
'/new_list' : (context) => ShoppingKartPage(),
'/stats' : (context) => StatPage(),
// When navigating to the "/second" route, build the SecondScreen widget.
// '/second': (context) => SecondScreen(),
},
),
);
});
}
}
class UserLoader extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("Version 1");
final ThemeData theme = Theme.of(context);
return FutureBuilder<void>(
future: UserDataContainer.of(context).widget.userdata.init(),
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
print("Build user");
return User();
} else {
return SplashScreen();
}
});
}
}
class SplashScreen extends StatefulWidget {
@override
_SplashScreenState createState() => new _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Image.asset('images/icon.png'),
),
);
}
}
物料应用程序具有我的路线,并且UserLoader在其中,因此我可以在启动时加载一些保存在手机上的用户数据。它会显示一个初始屏幕,然后等待数据加载完毕。
在我的抽屉中,我用指定的版本替换了要移动到特定页面的代码:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SettingsPage()));
蜜饯
Navigator.of(context).pop();
例如。
但是,现在当我使用该应用程序时,UserDataContainer有时包含一个全新的User()实例(这是一个dart类,而不是小部件),而且我不知道为什么该应用程序会突然出现这种情况。
编辑:
我尝试通过使用它而不是我的futureloader来删除FutureBuilder,但是UserContainer的状态每次都得到重建(尽管无需再次初始化):
class LoadingScreen extends StatefulWidget {
@override
_LoadingScreenState createState() => new _LoadingScreenState();
}
class _LoadingScreenState extends State<LoadingScreen>{
@override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_){
runInitTasks();
});
}
@protected
Future runInitTasks() async {
await UserDataContainer.of(context).widget.userdata.init();
Navigator.of(context).pushReplacementNamed('/fridge');
}
@override
Widget build(BuildContext context){
return Scaffold(
body: new Center(
child: new Image.asset('images/icon.png'),
),
);
}
}