当没有上下文可用时,如何从异步执行中显示SnackBar?

我有一个使用Flutter-

Redux的应用程序。在某些用户操作上,将分派各种还原操作,并且这些操作在中间件中异步运行。我现在的问题是:万一出问题了,我该如何从中间件中显示SnackBar。我不能使用回调,因为不能保证派发动作的Widget仍然可用。错误将是:

此时,小部件的元素树的状态不再稳定。要在其dispose()方法中安全地引用窗口小部件的祖先,请通过在窗口小部件的didChangeDependencies()方法中调用InheritFromWidgetOfExactType()来保存对祖先的引用。

例:

  1. 用户单击“保存”。
  2. 动作“保存到数据库”被异步调度。
  3. 动作“保存余下时间”异步发送。
  4. 对话框关闭。

现在…例如,当rest调用返回错误时,由于“很长一段时间”而关闭了该对话框,其上下文无效,并且我无法显示SnackBar。

进一步:

SnackBar必须始终绑定到脚手架。因此,我已经尝试制作一个空的root-

Scaffold并通过GlobalKey引用它。这就带来了一个问题,即当另一个窗口小部件位于根窗口小部件上方且用户无法读取时,SnackBar被隐藏了。

有什么建议如何解决这个问题?

最好的问候,弗洛里安

回答:

对于“一次性错误”,redux有点笨拙。一般来说,有两种处理方法:

  1. 您可以将错误保存在存储中,并在存储中存在错误时显示错误覆盖。从商店中删除错误以关闭覆盖。
  2. 将错误显示视为“一次性”副作用(就像播放声音一样)。我认为这是更好的解决方案,特别是如果您要使用小吃店。

我不确定中间件的外观如何,但是在网络请求失败后,您会将错误对象推送到rxdart

Subject或中StreamController。现在您有一个Stream错误。

作为您的直接子级StoreProvider,创建自己InheritedWidget的错误流,名为SyncErrorProvider

class SyncErrorProvider extends InheritedWidget {

const SyncErrorProvider({Key key, this.errors, @required Widget child})

: assert(child != null),

super(key: key, child: child);

final Stream<Object> errors;

static SyncErrorProvider of(BuildContext context) {

return context.inheritFromWidgetOfExactType(SyncErrorProvider) as SyncErrorProvider;

}

@override

bool updateShouldNotify(SyncErrorProvider old) => errors != old.errors;

}

继承的小部件应包装您的MaterialApp。现在,您有一种简单的方法,可以使用SyncErrorProvider.of(context).errorsfrom

从任何路径访问错误流didChangeDependencies


在小吃店中显示错误有点困难,因为小吃店的位置取决于页面布局(FAB,底部导航…),有时出现的小吃店会移动其他UI元素。

处理快餐栏创建的最佳方法实际上取决于您的应用程序。我也不确定这些错误会多久发生一次,所以也许不要花太多时间。

两种方法各有利弊:

回答:

在每个具有脚手架的屏幕中,侦听错误流并在本地脚手架中显示小吃店。确保在取消放置小部件时退订。

这种方法的优势在于,小吃栏是页面UI的一部分,并将移动支架的其他元素。

缺点是,如果存在对话框或没有支架的屏幕,则该错误将不可见。

class HomePage extends StatefulWidget {

@override

_HomePageState createState() => _HomePageState();

}

class _HomePageState extends State<HomePage> {

StreamSubscription _errorsSubscription;

final _scaffoldKey = GlobalKey<ScaffoldState>();

@override

void didChangeDependencies() {

super.didChangeDependencies();

if(_errorsSubscription == null) {

_errorsSubscription = SyncErrorProvider.of(context).errors.listen((error) {

_scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(error.toString())));

});

}

}

@override

void dispose() {

_errorsSubscription.cancel();

super.dispose();

}

@override

Widget build(BuildContext context) {

return Scaffold(

key: _scaffoldKey,

body: ...,

);

}

}

回答:

该脚手架仅用于小吃店,仅此而已。优点是始终保证错误是可见的,缺点是它们将与FAB和底部条重叠。

class MyApp extends StatefulWidget {

final Stream<Object> syncErrors; // coming from your store/middleware

MyApp({Key key, this.syncErrors}) : super(key: key);

@override

_MyAppState createState() => _MyAppState();

}

class _MyAppState extends State<MyApp> {

StreamSubscription _errorsSubscription;

final _errorScaffoldKey = GlobalKey<ScaffoldState>();

@override

void initState() {

// TODO: implement initState

super.initState();

_errorsSubscription = widget.syncErrors.listen((error) {

_errorScaffoldKey.currentState.showSnackBar(SnackBar(content: Text(error.toString())));

});

}

@override

void dispose() {

_errorsSubscription.cancel();

super.dispose();

}

@override

Widget build(BuildContext context) {

return MaterialApp(

builder: (context, child) {

Scaffold(

key: _errorScaffoldKey,

body: child,

);

},

);

}

}

以上是 当没有上下文可用时,如何从异步执行中显示SnackBar? 的全部内容, 来源链接: utcz.com/qa/400202.html

回到顶部