Flutter 在小部件重建后显示snackbar消息
我尝试登录页面(在将来的某个函数中执行事务),并通过Snackbar显示错误消息Flutter 在小部件重建后显示snackbar消息,flutter,dart,Flutter,Dart,我尝试登录页面(在将来的某个函数中执行事务),并通过Snackbar显示错误消息 单击登录 显示加载 未来事务已完成(返回原始页面),然后显示错误消息 以下是我想要实现的流程(最后一部分失败): 我不知道如何使用来自future的消息正确显示snackBar。 showSnackBar需要BuildContext,但在消息从Future返回后,登录页面内的上下文似乎不再有效 我现在使用包和用于状态管理 我的州 class MyState{ MyState({this.data,this.i
BuildContext
,但在消息从Future返回后,登录页面内的上下文似乎不再有效
我现在使用包和用于状态管理
我的州
class MyState{
MyState({this.data,this.isLoading});
final bool isLoading;
final String data;
MyState copyWith({data, isLoading}) => MyState(data: data, isLoading: isLoading);
}
状态控制和提供程序
Future getData()
获取数据并返回错误消息
class MyStateNotifier extends StateNotifier<MyState> {
MyStateNotifier(MyState state) : super(state);
Future<String> getData() async {
state = state.copyWith(isLoading: true);
await Future.delayed(Duration(seconds: 3)); // simulate getting data
state = state.copyWith(isLoading: false, data: 'some data');
return 'error message';
}
}
final myStateProvider = StateNotifierProvider<MyStateNotifier>((ref) {
return MyStateNotifier(MyState(data: null, isLoading: false));
});
我在中使用showSnackBar,然后在getData()之后使用,但它会显示错误消息:
E/flutter ( 6869): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: Looking up a
deactivated widget's ancestor is unsafe.
E/flutter ( 6869): At this point the state of the widget's element tree is no longer stable.
E/flutter ( 6869): To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
E/flutter ( 6869): #0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> (package:flutter/src/widgets/framework.dart:3938:9)
E/flutter ( 6869): #1 Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:3952:6)
E/flutter ( 6869): #2 Element.findAncestorWidgetOfExactType (package:flutter/src/widgets/framework.dart:4044:12)
E/flutter ( 6869): #3 debugCheckHasScaffoldMessenger.<anonymous closure> (package:flutter/src/material/debug.dart:142:17)
E/flutter ( 6869): #4 debugCheckHasScaffoldMessenger (package:flutter/src/material/debug.dart:154:4)
E/flutter ( 6869): #5 ScaffoldMessenger.of (package:flutter/src/material/scaffold.dart:218:12)
E/flutter ( 6869): #6 SignInPage.build.<anonymous closure>.<anonymous closure> (package:flutter_app_test2/main.dart:171:35)
E/flutter ( 6869): #7 _rootRunUnary (dart:async/zone.dart:1198:47)
E/flutter ( 6869): #8 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter ( 6869): #9 _FutureListener.handleValue (dart:async/future_impl.dart:143:18)
E/flutter ( 6869): #10 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:696:45)
E/flutter ( 6869): #11 Future._propagateToListeners (dart:async/future_impl.dart:725:32)
E/flutter ( 6869): #12 Future._completeWithValue (dart:async/future_impl.dart:529:5)
E/flutter ( 6869): #13 _completeOnAsyncReturn (dart:async-patch/async_patch.dart:254:13)
E/flutter ( 6869): #14 MyStateNotifier.getData (package:flutter_app_test2/main.dart)
E/flutter ( 6869): <asynchronous suspension>
E/flatter(6869):[错误:flatter/lib/ui/ui\u dart\u state.cc(177)]未处理的异常:查找
停用的小部件的祖先不安全。
E/flatter(6869):此时小部件元素树的状态不再稳定。
E/flatter(6869):为了在dispose()方法中安全地引用小部件的祖先,通过在小部件的didChangeDependencies()方法中调用dependOnInheritedWidgetOfExactType()保存对祖先的引用。
E/颤振(6869):#0元素。_调试检查状态为激活的组件。(包:flatter/src/widgets/framework.dart:3938:9)
E/flatter(6869):#1个元素。_debugCheckStateIsActiveForAncestorLookup(包:flatter/src/widgets/framework.dart:3952:6)
E/flatter(6869):#2 Element.findAncestorWidgetOfExactType(包:flatter/src/widgets/framework.dart:4044:12)
E/颤振(6869):#3调试检查HassCaffoldMessenger。(包装:颤振/src/material/debug.dart:142:17)
E/颤振(6869):#4调试检查HassCaffoldMessenger(包:颤振/src/材料/调试。dart:154:4)
E/颤振(6869):#5脚手架信使(包装:颤振/src/材料/脚手架。dart:218:12)
E/颤振(6869):#6个标志页。构建。。(包装:颤振试验2/main.省道:171:35)
E/flatter(6869):#7(dart:async/zone.dart:1198:47)
E/flatter(6869):#8_CustomZone.runUnary(dart:async/zone.dart:1100:19)
E/flatter(6869):#9 FutureListener.handleValue(dart:async/future_impl.dart:143:18)
E/flatter(6869):#10 Future._-propagateToListeners.handleValueCallback(dart:async/Future_-impl.dart:696:45)
E/颤振(6869):#11未来。(dart:async/Future\u impl.dart:725:32)
E/颤振(6869):#12未来。_完成值(dart:async/Future_impl.dart:529:5)
E/颤振(6869):#13完成同步返回(dart:async patch/async patch.dart:254:13)
E/flatter(6869):#14 MyStateNotifier.getData(包:flatter_app_test2/main.dart)
E/颤振(6869):
您必须等待getData()请求并以变量形式返回消息,然后调用snackbar。你试图在未来的通话中呼叫snackbar。这不能在UI上完成
final message = await context.read(myStateProvider).getData();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message)));
您必须等待getData()请求并以变量形式返回消息,然后调用snackbar。你试图在未来的通话中呼叫snackbar。这不能在UI上完成
final message = await context.read(myStateProvider).getData();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message)));
您可以复制粘贴运行下面的完整代码
原因:因为
登录页面
在单击登录
按钮后消失快速修复方法是使用
ScaffoldMessenger
并提供scaffoldMessengerKey
然后调用scaffoldMessengerKey.currentState.showSnackBar(SnackBar(内容:文本(消息))代码>
代码片段
final GlobalKey<ScaffoldMessengerState> scaffoldMessengerKey =
GlobalKey<ScaffoldMessengerState>();
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ScaffoldMessenger(
key: scaffoldMessengerKey,
child: Scaffold(
...
context.read(myStateProvider).getData().then(
(message) {
scaffoldMessengerKey.currentState
.showSnackBar(SnackBar(content: Text(message)));
},
);
最终GlobalKey脚手架信使钥匙=
GlobalKey();
类Home扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回脚手架信使(
钥匙:脚手架信使钥匙,
孩子:脚手架(
...
read(myStateProvider).getData()。然后(
(留言){
scaffoldMessengerKey.currentState
.showSnackBar(SnackBar(内容:文本(消息)));
},
);
工作演示
完整代码
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hooks_riverpod/all.dart';
class MyState {
MyState({this.data, this.isLoading});
final bool isLoading;
final String data;
MyState copyWith({data, isLoading}) =>
MyState(data: data, isLoading: isLoading);
}
class MyStateNotifier extends StateNotifier<MyState> {
MyStateNotifier(MyState state) : super(state);
Future<String> getData() async {
state = state.copyWith(isLoading: true);
await Future.delayed(Duration(seconds: 3)); // simulate getting data
state = state.copyWith(isLoading: false, data: 'some data');
return 'error message';
}
}
final myStateProvider = StateNotifierProvider<MyStateNotifier>((ref) {
return MyStateNotifier(MyState(data: null, isLoading: false));
});
void main() {
runApp(
const ProviderScope(child: MyApp()),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(home: Home());
}
}
final GlobalKey<ScaffoldMessengerState> scaffoldMessengerKey =
GlobalKey<ScaffoldMessengerState>();
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ScaffoldMessenger(
key: scaffoldMessengerKey,
child: Scaffold(
appBar: AppBar(title: const Text('example')),
body: WidgetA(),
),
);
}
}
class WidgetA extends HookWidget {
const WidgetA({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
final myState = useProvider(myStateProvider.state);
return Center(
child: myState.isLoading ? CircularProgressIndicator() : SignInPage(),
);
}
}
class SignInPage extends HookWidget {
const SignInPage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () async {
context.read(myStateProvider).getData().then(
(message) {
scaffoldMessengerKey.currentState
.showSnackBar(SnackBar(content: Text(message)));
},
);
},
child: Text('login'),
);
}
}
导入“包装:颤振/材料.省道”;
进口“包装:颤振钩/颤振钩.省道”;
进口“包装:颤振_riverpod/颤振_riverpod.dart”;
导入“包装:hooks_riverpod/all.dart”;
类MyState{
MyState({this.data,this.isLoading});
最终bool卸载;
最终字符串数据;
MyState copyWith({data,isLoading})=>
MyState(数据:数据,isLoading:isLoading);
}
类MyStateNotifier扩展了StateNotifier{
MyStateNotifier(MyState状态):超级(状态);
Future getData()异步{
state=state.copyWith(isLoading:true);
等待未来。延迟(持续时间(秒:3));//模拟获取数据
state=state.copyWith(isLoading:false,data:'some data');
返回“错误消息”;
}
}
最终myStateProvider=StateNotifierProvider((参考){
返回MyStateNotifier(MyState(数据:null,isLoading:false));
});
void main(){
runApp(
常量ProviderScope(子级:MyApp()),
);
}
类MyApp扩展了无状态小部件{
constmyapp({Key}):超级(Key:Key);
@凌驾
小部件构建(构建上下文){
返回物料app(home:home());
}
}
最终GlobalKey脚手架信使钥匙=
GlobalKey();
类Home扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回脚手架信使(
钥匙:脚手架信使钥匙,
孩子:脚手架(
appBar:appBar(标题:const Text('example')),
正文:WidgetA(),
),
);
}
}
类WidgetA扩展了HookWidget{
常量WidgetA({Key}):super(Key:Key);
@凌驾
小部件构建(构建上下文){
final myState=useProvider(myStateProvider.state);
返回中心(
子项:myState.isLoading?CircularProgressIndicator():SignInPage(),
);
}
}
类签名页扩展了Widget{
常量符号页({Key