我尝试执行登录页面(在未来函数中执行事务),并通过Snackbar显示错误消息。
下面是我想要实现的流程(最后一部分失败):
我不知道如何使用来自未来的消息正确地显示snackBar。
showSnackBar需要BuildContext
,但是在消息从未来返回之后,signIn页面中的上下文似乎不再有效了。
我的国家
class MyState{
MyState({this.data,this.isLoading});
final bool isLoading;
final String data;
MyState copyWith({data, isLoading}) => MyState(data: data, isLoading: isLoading);
}
状态控制和提供程序
Future<String> 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));
});
我的小部件
myState.isLoading
:显示加载页面或登录页面
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) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message)));
},
);
},
child: Text('login'),
);
}
}
我使用showSnackBar it ,然后在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>
发布于 2021-01-07 21:14:59
您可以复制粘贴,运行下面的完整代码
原因:因为SignInPage
在单击login
按钮后消失
快速修复是使用ScaffoldMessenger
并提供scaffoldMessengerKey
,然后调用scaffoldMessengerKey.currentState.showSnackBar(SnackBar(content: Text(message)));
代码段
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)));
},
);
工作演示
全码
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'),
);
}
}
发布于 2021-01-07 14:28:20
您必须等待getData()请求并返回变量中的消息,然后调用snackbar。你想在未来的电话里打电话给快餐店。这不能在UI上完成。
final message = await context.read(myStateProvider).getData();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message)));
https://stackoverflow.com/questions/65617100
复制