我正在尝试找到最佳方法,以通过Snackbar从带有提供程序的更改通知程序模型中显示错误。
有没有内置的方法或建议可以帮助我?
我发现这种方式有效,但我不知道它是否正确。
假设我有一个简单的Page要在其中显示对象列表,而Model则需要从api检索这些对象。如果发生错误,我会通知错误字符串,并希望通过SnackBar显示该错误。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Page extends StatefulWidget {
Page({Key key}) : super(key: key);
@override
_PageState createState() => _PageState();
}
class _PageState extends State< Page > {
@override
void initState(){
super.initState();
Provider.of<Model>(context, listen: false).load();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
Provider.of< Model >(context, listen: false).addListener(_listenForErrors);
}
@override
Widget build(BuildContext context){
super.build(context);
return Scaffold(
appBar: AppBar(),
body: Consumer<Model>(
builder: (context, model, child){
if(model.elements != null){
...list
}
else return LoadingWidget();
}
)
)
);
}
void _listenForErrors(){
final error = Provider.of<Model>(context, listen: false).error;
if (error != null) {
Scaffold.of(context)
..hideCurrentSnackBar()
..showSnackBar(
SnackBar(
backgroundColor: Colors.red[600],
content: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(Icons.error),
Expanded(child: Padding( padding:EdgeInsets.only(left:16), child:Text(error) )),
],
),
),
);
}
}
@override
void dispose() {
Provider.of<PushNotificationModel>(context, listen: false).removeListener(_listenForErrors);
super.dispose();
}
}
import 'package:flutter/foundation.dart';
class BrickModel extends ChangeNotifier {
List<String> _elements;
List<String> get elements => _elements;
String _error;
String get error => _error;
Future<void> load() async {
try{
final elements = await someApiCall();
_elements = [..._elements, ...elements];
}
catch(e) {
_error = e.toString();
}
finally {
notifyListeners();
}
}
}
谢谢
答案 0 :(得分:1)
谢谢。
也许我找到了一种更简单的方法来处理此问题,即使用Consumer强大的属性“ child”。
使用自定义的无状态窗口小部件(我将其称为ErrorListener,但可以对其进行更改:))
class ErrorListener<T extends ErrorNotifierMixin> extends StatelessWidget {
final Widget child;
const ErrorListener({Key key, @required this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return Consumer<T>(
builder: (context, model, child){
//here we listen for errors
if (model.error != null) {
WidgetsBinding.instance.addPostFrameCallback((_){
_handleError(context, model); });
}
// here we return child!
return child;
},
child: child
);
}
// this method will be called anytime an error occurs
// it shows a snackbar but it could do anything you want
void _handleError(BuildContext context, T model) {
Scaffold.of(context)
..hideCurrentSnackBar()
..showSnackBar(
SnackBar(
backgroundColor: Colors.red[600],
content: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(Icons.error),
Expanded(child: Padding( padding:EdgeInsets.only(left:16), child:Text(model.error) )),
],
),
),
);
// this will clear the error on model because it has been handled
model.clearError();
}
}
如果您想使用小吃店,则必须将此小部件放在支架下。
我在这里使用mixin来确保模型具有error
属性和clarError()
方法。
mixin ErrorNotifierMixin on ChangeNotifier {
String _error;
String get error => _error;
void notifyError(dynamic error) {
_error = error.toString();
notifyListeners();
}
void clearError() {
_error = null;
}
}
例如,我们可以使用这种方式
class _PageState extends State<Page> {
// ...
@override
Widget build(BuildContext context) =>
ChangeNotifierProvider(
builder: (context) => MyModel(),
child: Scaffold(
body: ErrorListener<MyModel>(
child: MyBody()
)
)
);
}
答案 1 :(得分:0)
您可以创建自定义FormatException: Invalid length, must be multiple of four (at character 183)
...jLTQxMDctYjUzNC1hOGZiOTNhMzEwNzAiLCJuYW1lIjoiTGVuIiwiaWF0IjoxNTczMDI4MjU2fQ
,以在视图模型更改时启动小吃栏。例如:
StatelessWidget
只有在所有小部件都构建好后,我们才能显示小吃店,这就是我们在上面进行class SnackBarLauncher extends StatelessWidget {
final String error;
const SnackBarLauncher(
{Key key, @required this.error})
: super(key: key);
@override
Widget build(BuildContext context) {
if (error != null) {
WidgetsBinding.instance.addPostFrameCallback(
(_) => _displaySnackBar(context, error: error));
}
// Placeholder container widget
return Container();
}
void _displaySnackBar(BuildContext context, {@required String error}) {
final snackBar = SnackBar(content: Text(error));
Scaffold.of(context).hideCurrentSnackBar();
Scaffold.of(context).showSnackBar(snackBar);
}
}
调用的原因。
现在我们可以在屏幕上添加WidgetsBinding.instance.addPostFrameCallback()
:
SnackBarLauncher