我不知道要查找什么,所以请随时给我一些关于在哪里查找的指示。我正在学习,所以这绝对值得赞赏。
我刚刚发现我可以在颤动中使用命名路由,并且我正试图转向事物以使我的应用程序的行为更可预测。但是,在某些时候,我的 UserDataContainer Stateful Widget 会丢失他的状态值。所以我有一些用户数据,它消失了。
这是一些代码。
这是我的用户数据容器:
// 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'),
),
);
}
}