Flutter 在小部件重建后显示snackbar消息

Flutter 在小部件重建后显示snackbar消息,flutter,dart,Flutter,Dart,我尝试登录页面(在将来的某个函数中执行事务),并通过Snackbar显示错误消息 单击登录 显示加载 未来事务已完成(返回原始页面),然后显示错误消息 以下是我想要实现的流程(最后一部分失败): 我不知道如何使用来自future的消息正确显示snackBar。 showSnackBar需要BuildContext,但在消息从Future返回后,登录页面内的上下文似乎不再有效 我现在使用包和用于状态管理 我的州 class MyState{ MyState({this.data,this.i

我尝试登录页面(在将来的某个函数中执行事务),并通过Snackbar显示错误消息

  • 单击登录
  • 显示加载
  • 未来事务已完成(返回原始页面),然后显示错误消息
  • 以下是我想要实现的流程(最后一部分失败):

    我不知道如何使用来自future的消息正确显示snackBar。

    showSnackBar需要
    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