如何在热重载时使用 Provider 维护 Flutter Global BloC 状态?
How to maintain Flutter Global BloC state using Provider on Hot Reload?
每当执行热重载时,我似乎都会丢失应用程序状态。
我正在使用 BloC 提供程序来存储应用程序状态。这在 main.dart 中的应用级别传递并在子页面上使用。在视图的初始加载时,会显示该值。我可以在应用程序中导航并且状态持续存在。但是,当我执行热重载时,我丢失了值和状态。
如何解决此问题以便在热重载时保留状态?
区块提供商
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();
}
}
你正在失去状态,因为你的 bloc 正在 _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
方法,该方法在小部件状态重建时调用。
请记住,如果您在您的区域中使用非广播流,那么如果您尝试收听已经在收听的流,则可能会出现异常。
我遇到了同样的问题。继承的小部件使得很难处理 bloc 的资源。
另一方面,有状态小部件允许处理,但在您使用的实现中,它不会将 bloc 保持在状态中,导致小部件重建时状态丢失。
经过一些试验,我想出了一种将两者结合起来的方法:
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 提供给嵌套的 widget。
所有区块都扩展了 BlocBase class
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(),
));
}
每当执行热重载时,我似乎都会丢失应用程序状态。
我正在使用 BloC 提供程序来存储应用程序状态。这在 main.dart 中的应用级别传递并在子页面上使用。在视图的初始加载时,会显示该值。我可以在应用程序中导航并且状态持续存在。但是,当我执行热重载时,我丢失了值和状态。
如何解决此问题以便在热重载时保留状态?
区块提供商
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();
}
}
你正在失去状态,因为你的 bloc 正在 _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
方法,该方法在小部件状态重建时调用。
请记住,如果您在您的区域中使用非广播流,那么如果您尝试收听已经在收听的流,则可能会出现异常。
我遇到了同样的问题。继承的小部件使得很难处理 bloc 的资源。 另一方面,有状态小部件允许处理,但在您使用的实现中,它不会将 bloc 保持在状态中,导致小部件重建时状态丢失。
经过一些试验,我想出了一种将两者结合起来的方法:
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 提供给嵌套的 widget。
所有区块都扩展了 BlocBase class
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(),
));
}