首页 > 解决方案 > 用于聊天应用程序的 Flutter 中的 FutureBuilder

问题描述

我正在使用 firebase 身份验证创建一个群聊应用程序。我的应用程序流程是这样的,我让用户注册和登录。一旦用户注册或登录,他/她将被带到聊天屏幕,他们可以在其中发送消息。登录流程工作正常。但是在创建新用户时,我无法在聊天屏幕上检索用户数据。这是我的代码示例。

这就是我在屏幕之间切换的方式。

Scaffold(
    body: StreamBuilder(
        builder: (context, snapshot) {
          if (snapshot.hasData &&
              snapshot.connectionState == ConnectionState.active) {
            return ChatScreen();
          } else {
            return AuthScreen();
          }
        },
        stream: FirebaseAuth.instance.authStateChanges()));

这是用于注册和登录用户的代码。

class _AuthScreenState extends State<AuthScreen> {
final _auth = FirebaseAuth.instance;
var _isLoading = false;

void _submitAuthForm(
String email,
String password,
String username,
bool isLogin,
File f,
BuildContext ctx,
) async {
UserCredential authResult;

try {
  final collection = FirebaseFirestore.instance.collection('users');
  var imageUrl = '';
  setState(() {
    _isLoading = true;
  });
  if (isLogin) {
    authResult = await _auth.signInWithEmailAndPassword(
      email: email,
      password: password,
    );
  } else {
    authResult = await _auth.createUserWithEmailAndPassword(
      email: email,
      password: password,
    );
    final ref = FirebaseStorage.instance
        .ref()
        .child('user_image')
        .child(authResult.user.uid);

    // await ref
    //     .putFile(f)
    //     .whenComplete(() async => imageUrl = await ref.getDownloadURL());

    await ref.putFile(f);
    final url = await ref.getDownloadURL();

    collection.doc(authResult.user.uid).set({
      'username': username,
      'email': email,
      'password': password,
      'imageFile': url
    });
  }
} on FirebaseAuthException catch (err) {
  String errorMessage = '';
  if (err.code == 'weak-password') {
    errorMessage = 'The password provided is too weak.';
  } else if (err.code == 'email-already-in-use') {
    errorMessage = 'The account already exists for that email.';
  } else if (err.code == 'user-not-found') {
    errorMessage = 'No user found for that email.';
  } else if (err.code == 'wrong-password') {
    errorMessage = 'Wrong password provided for that user.';
  } 
  
  Scaffold.of(ctx).showSnackBar(
    SnackBar(
      content: Text(errorMessage),
      backgroundColor: Theme.of(ctx).errorColor,
    ),
  );
  setState(() {
    _isLoading=false;
  });
} on PlatformException catch (err) {
  var message = 'An error occurred, pelase check your credentials!';

  if (err.message != null) {
    message = err.message;
  }

  Scaffold.of(ctx).showSnackBar(
    SnackBar(
      content: Text(message),
      backgroundColor: Theme.of(ctx).errorColor,
    ),
  );
  setState(() {
    _isLoading = false;
  });
} catch (err) {
  setState(() {
    _isLoading = false;
  });
  if (_isLoading == false) {
    Scaffold.of(context).showSnackBar(SnackBar(
      backgroundColor: Theme.of(context).errorColor,
      content: Text(err.toString()),
    ));
  }
}

}

此方法负责从用户集合中检索用户数据。

Future<User> getUserByUid(String uid) async {
  final doc = await collection.doc(uid).get();
   return User.fromJSON(doc.data());
}

这个负责在聊天屏幕上显示数据。

class ChatScreen extends StatefulWidget {
@override
_ChatScreenState createState() => _ChatScreenState();
}

class _ChatScreenState extends State<ChatScreen> {
var future;
@override
void initState() {
super.initState();
future= FirebaseService()
        .getUserByUid(FirebaseAuth.instance.currentUser.uid);

}
@override
Widget build(BuildContext context) {
return FutureBuilder(
    future: _user,
    builder: (context, snapshot) {
       if (snapshot.connectionState == ConnectionState.done &&
          snapshot.hasData) {
        
        return Scaffold(
            appBar: AppBar(
              toolbarHeight: 70,
              leading: Container(
                  margin: EdgeInsets.fromLTRB(10, 0, 0, 0),
                  child: InkWell(
                    onTap: () {
                      Navigator.of(context)
                          .pushNamed(SettingsScreen.routeName);
                    },
                    child: CircleAvatar(
                      backgroundImage: snapshot.data.imageUrl != null
                          ? NetworkImage(snapshot.data.imageUrl)
                          : null,
                    ),
                  )),
              title: Text(
                snapshot.data.username,
                style: TextStyle(color: Colors.black),
              ),
              backgroundColor: Colors.white,
              actions: [
                IconButton(
                    color: Colors.white,
                    icon: RadiantGradientMask(
                        child: FaIcon(FontAwesomeIcons.userFriends)),
                    onPressed: () {
                      Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (context) => ListOfFriends()));
                    }),
                IconButton(
                  //color: Colors.deepPurple,
                  tooltip: 'Logout',
                  icon: RadiantGradientMask(
                      child: FaIcon(FontAwesomeIcons.signOutAlt)),
                  onPressed: () {
                    FirebaseAuth.instance.signOut();
                  },
                )
              ],
              elevation: 0.5,
              centerTitle: true,
            ),
            body: Column(
              children: [
                Expanded(child: Messages()),
                NewMessage(),
              ],
            ));
      } else {
        
        return Center(child: CircularProgressIndicator());
      }
    });

} }

这段代码永远不会出现在 if 块中,并且循环进度指示器会永远持续下去。任何帮助将不胜感激,在此先感谢。

标签: flutterdartmobile-application

解决方案


首先避免将你的未来命名为未来。

回答你:

final Future<String> _user; // add prefix 'late' if you are already using sound null safety.

Future<String> _getUserByUID(final var uid) async {
    return await FirebaseService().getUserByUid(uid);
}

@override
void initState() {
    super.initState();
    _user = _getUserByUID(FirebaseAuth.instance.currentUser.uid);
}

[...]

return FutureBuilder(
    future: _user,

[...]

if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
      print('the data is ${snapshot.data}');
      return Scaffold(
          appBar: AppBar(
       [...]
));} else
     return Center(child: CircularProgressIndicator());
}

现在它应该可以工作了,让我知道它是否解决了它!

编辑:您必须添加snapshot.hasData条件,否则您的代码可能会为空;


推荐阅读