Http 颤振:如何从不是小部件的类中调用SnackBar
我从Flatter开始,制作了一个简单的应用程序,使用RESTAPI管理登录屏幕 我使用http包和包截获并发送头中的令牌 问题是。。。我可以用拦截器捕获错误,没有任何问题。但是,有没有办法使用一个全局snackbar,它可以从我的拦截器类“通知”并将用户重定向到显示应用程序中任何错误的登录屏幕,例如,当令牌无效时 这是我的拦截器类:Http 颤振:如何从不是小部件的类中调用SnackBar,http,flutter,interceptor,snackbar,Http,Flutter,Interceptor,Snackbar,我从Flatter开始,制作了一个简单的应用程序,使用RESTAPI管理登录屏幕 我使用http包和包截获并发送头中的令牌 问题是。。。我可以用拦截器捕获错误,没有任何问题。但是,有没有办法使用一个全局snackbar,它可以从我的拦截器类“通知”并将用户重定向到显示应用程序中任何错误的登录屏幕,例如,当令牌无效时 这是我的拦截器类: class ApiInterceptor with ChangeNotifier implements InterceptorContract { final
class ApiInterceptor with ChangeNotifier implements InterceptorContract {
final storage = new FlutterSecureStorage();
@override
Future<RequestData> interceptRequest({RequestData data}) async {
[...] // here is the request interceptor
return data;
}
// The response interceptor:
@override
Future<ResponseData> interceptResponse({ResponseData data}) async {
final decodedResponse = json.decode(data.body);
if (data.statusCode >= 400) {
throw HttpException(decodedResponse['error']);
// here i want to send the notification to a snackBar
// then, i want to redirect the user to the login screen
}
return data;
}
}
使用MultipleProvider
widget在my main.dart上调用这些提供程序:
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: ApiInterceptor(),
),
ChangeNotifierProvider.value(
value: Auth(),
),
ChangeNotifierProvider.value(
value: TurnActive(),
),
],
child: MaterialApp(
.
.
.
[UPDATE II]
这是更新后的main.dart
。。。但仍然不起作用
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
final storage = new FlutterSecureStorage();
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'CAD App',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: Scaffold(
body: MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: ApiInterceptor(context: context),
),
ChangeNotifierProvider.value(
value: Auth(context: context),
),
ChangeNotifierProvider.value(
value: TurnActive(context: context),
),
],
child: FutureBuilder(
future: storage.read(key: "token"),
builder: (context, storedKey) {
if (!storedKey.hasData) {
return LoadingData(text: 'Por favor espere...');
} else {
return storedKey.data == null
? LoginPage()
: InitialLoadingPage();
}
},
),
),
),
);
}
}
在我的拦截器上:
.
.
.
@override
Future<ResponseData> interceptResponse({ResponseData data}) async {
final decodedResponse = json.decode(data.body);
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(decodedResponse['error']),
));
.
.
.
。
.
.
@凌驾
未来侦听响应({ResponseData})异步{
final decodedResponse=json.decode(data.body);
Scaffold.of(上下文).showSnackBar(SnackBar(
内容:文本(decodedResponse['error']),
));
.
.
.
错误是:
Scaffold.of()使用不包含Scaffold的上下文调用。
最新答案
最初的答案将BuildContext
传递到您的ChangeNotifier
服务中,该服务在技术上是有效的,但在查看后,我意识到它非常不专业。这是因为使用提供者
或服务的整个概念是将小部件构建和后台功能分开。传递BuildContext
和从服务内部创建一个Snackbar
并不是很好。Bellow是一个更专业、稍微多一些的工作,可以让你的头脑围绕它,但从长远来看更灵活
想法
因此,所有小部件
代码都包含在您用于UI和UX的类中,您需要在类中具有某种类型的函数,但只能从APInterceptor
调用。为此,您将使用可应用于变量的所谓函数
步骤1:创建typedef
您的typedef
应该在类之外创建,但仍然在要应用它的主文件中,最好是在包含apinterceptor
的文件中
typedef void OnInterceptError(字符串错误消息);
如果您从未在任何语言中使用过typedef
,您可能会感到非常困惑。您所做的只是创建一个函数类型,它返回void
,并以字符串
作为输入
步骤2:在apinterceptor内使用OnInterceptError
apinterceptor({
@此错误是必需的,
}):assert(interceptError!=null);
最终OnInterceptorThis.interceptError;
//响应拦截器
@凌驾
未来侦听响应({ResponseData})异步{
final decodedResponse=json.decode(data.body);
如果(data.statusCode>=400){
抛出HttpException(decodedResponse['error']);
//运行“interceptError”将通知发送到
//“小吃吧`
截取错误(decodedResponse['error']);
}
返回数据;
}
设置好这个之后,你终于可以进入好的部分了:设置UI
步骤3:创建onInterceptorror
函数。。。
现在您已经知道了函数的运行位置,您需要创建函数具有其…功能的位置
无论您在何处实现此apinterceptor
服务,现在都应该传递以下内容
apinterceptor(
interceptError:(字符串errorMessage){
//从这里显示“Snackbar”,它应该有
//访问“BuildContext”以执行此操作并使用
//`interceptError`来为
//“Snackbar”,如果你愿意的话。
打印(错误);
}
);
一开始它看起来非常复杂,但它确实是一种很好的方法,因为它将您的服务和UI分开
原始答案
不幸的是,由于Dart的工作原理,抓取BuildContext
可能有点麻烦,但100%可能。我将引导您完成以下步骤:
步骤1:在apinterceptor
当前,您的apinterceptor
类被声明为没有任何输入变量,因此您将在顶部向类添加以下内容
apinterceptor({
@在这种情况下,
}):assert(上下文!=null);
最终构建语境;
现在,每次在代码库中访问类时,IDE都会通知您缺少一个变量
步骤2:在Auth
遗憾的是,您必须对Auth
提供程序执行完全相同的操作。我将为您保留与上一步相同的独白,因为它们几乎是相同的过程。以下是您必须添加到Auth
类开头的内容
Auth({
@在这种情况下,
}):assert(上下文!=null);
最终构建语境;
步骤3:在每个必需的情况下传递BuildContext
您可能会发现,IDE为您完成了大部分工作!以下是所有类的完整代码
带有ChangeNotifier的类APInterceptor实现InterceptorContract{
API拦截器({
@在这种情况下,
}):assert(上下文!=null);
最终构建语境;
最终存储=新存储();
@凌驾
未来拦截请求({RequestData})异步{
[…]//这是请求拦截器
返回数据;
}
//响应拦截器:
@凌驾
未来侦听响应({ResponseData})异步{
final decodedResponse=json.d
.
.
.
@override
Future<ResponseData> interceptResponse({ResponseData data}) async {
final decodedResponse = json.decode(data.body);
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(decodedResponse['error']),
));
.
.
.