每当我执行热重载时,我似乎都失去了应用程序状态。
我正在使用BloC提供程序来存储应用程序状态。这是在main.dart中的App级别传递的,并在子页面上使用。在视图的初始加载时,将显示该值。我可以浏览应用程序,状态仍然存在。但是,当我执行热重载时,我会丢失值,看似状态。
如何解决此问题以便在Hot Reload上保留状态?
集团提供商
abstract class BlocBase {
void dispose();
}
class BlocProvider<T extends BlocBase> extends StatefulWidget {
BlocProvider({
Key key,
@required this.child,
@required this.bloc,
}): super(key: key);
final T bloc;
final Widget child;
@override
_BlocProviderState<T> createState() => _BlocProviderState<T>();
static T of<T extends BlocBase>(BuildContext context){
final type = _typeOf<BlocProvider<T>>();
BlocProvider<T> provider = context.ancestorWidgetOfExactType(type);
return provider.bloc;
}
static Type _typeOf<T>() => T;
}
class _BlocProviderState<T> extends State<BlocProvider<BlocBase>>{
@override
void dispose(){
widget.bloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context){
return widget.child;
}
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return BlocProvider<ApplicationStateBloc>(
bloc: ApplicationStateBloc(),
child: MaterialApp(
title: 'Handshake',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: LoadingPage(),
)
);
}
}
class ProfileSettings extends StatefulWidget {
@override
_ProfileSettingsState createState() => _ProfileSettingsState();
}
class _ProfileSettingsState extends State<ProfileSettings>{
ApplicationStateBloc _applicationStateBloc;
@override
void initState() {
super.initState();
_applicationStateBloc = BlocProvider.of<ApplicationStateBloc>(context);
}
@override
void dispose() {
_applicationStateBloc?.dispose();
super.dispose();
}
Widget emailField() {
return StreamBuilder<UserAccount>(
stream: _applicationStateBloc.getUserAccount,
builder: (context, snapshot){
if (snapshot.hasData) {
return Text(snapshot.data.displayName, style: TextStyle(color: Color(0xFF151515), fontSize: 16.0),);
}
return Text('');
},
);
}
@override
Widget build(BuildContext context) {
return BlocProvider<ApplicationStateBloc>(
bloc: _applicationStateBloc,
child: Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: Column(
children: <Widget>[
emailField(),
.... // rest of code
class ApplicationStateBloc extends BlocBase {
var userAccountController = BehaviorSubject<UserAccount>();
Function(UserAccount) get updateUserAccount => userAccountController.sink.add;
Stream<UserAccount> get getUserAccount => userAccountController.stream;
@override
dispose() {
userAccountController.close();
}
}
我遇到了同样的问题。继承的小部件使得很难处理集团的资源。另一方面,有状态窗口小部件允许处理,但在实现中,您使用它并不会将状态持久化,从而导致窗口小部件重建时状态丢失。
经过一些实验,我想出了一种方法,将两者结合起来:
class BlocHolder<T extends BlocBase> extends StatefulWidget {
final Widget child;
final T Function() createBloc;
BlocHolder({
@required this.child,
@required this.createBloc
});
@override
_BlocHolderState createState() => _BlocHolderState();
}
class _BlocHolderState<T extends BlocBase> extends State<BlocHolder> {
T _bloc;
Function hello;
@override
void initState() {
super.initState();
_bloc = widget.createBloc();
}
@override
Widget build(BuildContext context) {
return BlocProvider(
child: widget.child,
bloc: _bloc,
);
}
@override
void dispose() {
_bloc.dispose();
super.dispose();
}
}
Bloc holder在createState()中创建bloc并保持它。它还在dispose()中处理bloc的资源。
class BlocProvider<T extends BlocBase> extends InheritedWidget {
final T bloc;
const BlocProvider({
Key key,
@required Widget child,
@required T bloc,
})
: assert(child != null),
bloc = bloc,
super(key: key, child: child);
static T of<T extends BlocBase>(BuildContext context) {
final provider = context.inheritFromWidgetOfExactType(BlocProvider) as BlocProvider;
return provider.bloc;
}
@override
bool updateShouldNotify(BlocProvider old) => false;
}
顾名思义,BlocProvider只负责为嵌套小部件提供bloc。
所有集团都扩展了BlocBase类
abstract class BlocBase {
void dispose();
}
这是一个用法示例:
class RouteHome extends MaterialPageRoute<ScreenHome> {
RouteHome({List<ModelCategory> categories, int position}): super(builder:
(BuildContext ctx) => BlocHolder(
createBloc: () => BlocMain(ApiMain()),
child: ScreenHome(),
));
}
你正在失去状态,因为你的集团正在_ProfileSettingsState
的initState()
中被检索,因此,即使你热重新加载它也不会改变,因为该方法只在构建小部件时被调用一次。
在返回build()
之前,将其移至BlocProvider
方法
@override
Widget build(BuildContext context) {
_applicationStateBloc = BlocProvider.of<ApplicationStateBloc>(context);
return BlocProvider<ApplicationStateBloc>(
bloc: _applicationStateBloc,
child: Scaffold(
backgroundColor: Colors.white,
....
或者随时调用窗口小部件状态的didUpdateWidget
方法。
请记住,如果您在集团中使用非广播流,则在尝试收听已经收听的流时可能会出现异常。