You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中Consumer触发类型错误:期望(() => void)?却得到_Future<dynamic>

Flutter Google登录点击按钮抛出类型错误问题

问题现象

未登录页面可正常显示,但点击登录按钮时抛出以下类型异常:

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following TypeErrorImpl was thrown building Consumer<ControllerLogin>(dirty, dependencies:
[_InheritedProviderScope<ControllerLogin?>]):
Expected a value of type '(() => void)?', but got one of type '_Future<dynamic>'

The relevant error-causing widget was:
  Consumer<ControllerLogin>
  Consumer:file:///E:/CoderLife/Learning/flutter-learning/google_signin_authentication/lib/loginScreen.dart:17:12

相关代码

登录页面UI控制逻辑

loginUIController() {
    return Consumer<ControllerLogin>(builder: (context, model, child) {
      // 若用户已登录
      if (model.userModel != null) {
        return Center(
          // 展示用户详情
          child: alreadyLoggedInScreen(model),
        );
      } else {
        // 若用户未登录
        return notLoginScreen(model);
      }
    });
  }

未登录页面实现

notLoginScreen(ControllerLogin model) {
    return Center(
      child: Column(
        children: [
          Padding(
            padding: EdgeInsets.all(10),
            child: Image.asset('assets/googleback.jpg'),
          ),
          GestureDetector(
            onTap: () {
              Provider.of<ControllerLogin>(context, listen: false).allowUserToLogin();
            },
            child: Image.asset(
              'assets/google.png',
              width: 250,
            ),
          )
        ],
      ),
    );
  }

页面构建方法

Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: loginUIController(),
    );
  }

ControllerLogin状态管理类

class ControllerLogin with ChangeNotifier {
  FirebaseAuth auth = FirebaseAuth.instance;
  var googleSignIn = GoogleSignIn();
  GoogleSignInAccount? googleSignInAccount;
  UserCredential? userCredential;

  UserModel? userModel;
  User? user;

  allowUserToLogin() async {
    if (kIsWeb) {
      GoogleAuthProvider authProvider = GoogleAuthProvider();

      try {
        userCredential = await auth.signInWithPopup(authProvider);
        user = userCredential!.user;
      } catch (e) {
        print(e);
      }
    } else {
      googleSignInAccount = await googleSignIn.signIn();
      if (googleSignInAccount != null) {
        final GoogleSignInAuthentication googleSignInAuthentication =
            await googleSignInAccount!.authentication;
        final AuthCredential credential = GoogleAuthProvider.credential(
          accessToken: googleSignInAuthentication.accessToken,
          idToken: googleSignInAuthentication.idToken,
        );

        try {
          userCredential = await auth.signInWithCredential(credential);
          user = userCredential!.user;
        } on FirebaseAuthException catch (e) {
          if (e.code == 'account-exists-with-different-credential') {
            print(e);
          } else if (e.code == 'invalid-credential') {
            print(e);
          }
        } catch (e) {
          print(e);
        }
      }
    }

    if (user != null) {
      userModel = new UserModel(
          displayName: user!.displayName,
          email: user!.email,
          photoUrl: user!.photoURL);

      print(userModel!.toJson());

      notifyListeners();
    }
  }

  allowUserToLogOut() async {
    this.googleSignInAccount = await googleSignIn.signOut();

    userModel = null;

    notifyListeners();
  }
}

Provider初始化代码

Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => ControllerLogin()),
      ],
      child: MaterialApp(
        title: 'Google Login',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: FutureBuilder(
          future: _initApp,
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            if (snapshot.hasError) {
              print('error');
            }
            if (snapshot.connectionState == ConnectionState.done) {
              return LoginScreen();
            }
            return CircularProgressIndicator();
          },
        ),
      ),
    );
  }

错误原因

核心问题在于notLoginScreen方法中:

  1. 该方法未接收BuildContext参数,直接使用的context是无效的,导致Provider.of调用时上下文不匹配
  2. 虽然allowUserToLogin是异步方法,但onTap只要求返回void的回调,之前修改异步函数的方向正确,但没解决上下文的根本问题

解决方案

推荐方案:直接使用Consumer提供的model调用方法

既然已经通过Consumer获取了ControllerLogin实例,无需再调用Provider.of,直接使用传入的model调用登录方法即可,避免上下文问题:

notLoginScreen(ControllerLogin model) {
    return Center(
      child: Column(
        children: [
          Padding(
            padding: EdgeInsets.all(10),
            child: Image.asset('assets/googleback.jpg'),
          ),
          GestureDetector(
            onTap: () async {
              // 直接使用传入的model调用异步登录方法
              await model.allowUserToLogin();
            },
            child: Image.asset(
              'assets/google.png',
              width: 250,
            ),
          )
        ],
      ),
    );
  }

备选方案:传递有效BuildContext参数

修改notLoginScreen方法,让它接收BuildContext参数,确保Provider.of使用有效上下文:

// 修改方法签名,添加context参数
notLoginScreen(BuildContext context, ControllerLogin model) {
    return Center(
      child: Column(
        children: [
          Padding(
            padding: EdgeInsets.all(10),
            child: Image.asset('assets/googleback.jpg'),
          ),
          GestureDetector(
            onTap: () async {
              Provider.of<ControllerLogin>(context, listen: false).allowUserToLogin();
            },
            child: Image.asset(
              'assets/google.png',
              width: 250,
            ),
          )
        ],
      ),
    );
  }

同时在Consumer中调用时传入context:

loginUIController() {
    return Consumer<ControllerLogin>(builder: (context, model, child) {
      if (model.userModel != null) {
        return Center(
          child: alreadyLoggedInScreen(model),
        );
      } else {
        // 传入有效context
        return notLoginScreen(context, model);
      }
    });
  }

内容的提问来源于stack exchange,提问作者Leon W

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 23:25:32