2017-08-22 91 views
1

访问currentUser数据在我的应用程序,我有一个UserAccountsDrawerHeader,我通过简单地从获得x属性FirebaseAuth.instance.currentUser.x在firebase_auth插件版本0.2.0

养活它的属性抽屉

在最新的firebase_auth 0.2.0版本中,其中currentUser()是异步的。

我一直在尝试几个小时来存储当前登录的用户的信息,还没有达到正确的方式来做到这一点。

我明白,我可以像下面这样访问他们:

Future<String> _getCurrentUserName() async { 
    FirebaseUser user = await FirebaseAuth.instance.currentUser(); 
    return user.displayName; 
} 

...

new UserAccountsDrawerHeader(accountName: new Text(_getCurrentUserName())) 

我明白这些代码片段会给类型不匹配,但我只是想来说明我正在尝试做什么。

我究竟错过了什么,阻止了我达成解决方案?

更新

class _MyTabsState extends State<MyTabs> with TickerProviderStateMixin { 
    TabController controller; 
    Pages _page; 
    String _currentUserName; 
    String _currentUserEmail; 
    String _currentUserPhoto; 
    @override 
    void initState() { 
    super.initState(); 
    _states(); 
    controller = new TabController(length: 5, vsync: this); 
    controller.addListener(_select); 
    _page = pages[0]; 
    } 

我的方法

我只是加上我先前实施的TabBar状态AUTH状态

_states() async{ 
    var user = await FirebaseAuth.instance.currentUser(); 
    var name = user.displayName; 
    var email = user.email; 
    var photoUrl = user.photoUrl; 
    setState(() { 
     this._currentUserName=name; 
     this._currentUserEmail=email; 
     this._currentUserPhoto=photoUrl; 
     _page = pages[controller.index]; 
    }); 
    } 

我的抽屉里

drawer: new Drawer(
     child: new ListView(
      children: <Widget>[ 
      new UserAccountsDrawerHeader(accountName: new Text(_currentUserName) , 
       accountEmail: new Text (_currentUserEmail), 
       currentAccountPicture: new CircleAvatar(
       backgroundImage: new NetworkImage(_currentUserPhoto), 
      ), 

这里是例外我从调试控制台

I/flutter (14926): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ 
I/flutter (14926): The following assertion was thrown building MyTabs(dirty, state: _MyTabsState#f49aa(tickers: 
I/flutter (14926): tracking 1 ticker)): 
I/flutter (14926): 'package:flutter/src/widgets/text.dart': Failed assertion: line 207 pos 15: 'data != null': is not 
I/flutter (14926): true. 
I/flutter (14926): Either the assertion indicates an error in the framework itself, or we should provide substantially 

更新得到2:

我这是怎么修改的谷歌标志的功能从火力点的例子:

Future <FirebaseUser> _testSignInWithGoogle() async { 
     final GoogleSignInAccount googleUser = await _googleSignIn.signIn(); 
     final GoogleSignInAuthentication googleAuth = 
     await googleUser.authentication; 
//checking if there is a current user 
     var check = await FirebaseAuth.instance.currentUser(); 
     if (check!=null){ 
     final FirebaseUser user = check; 
     return user; 
     } 
     else{ 
     final FirebaseUser user = await _auth.signInWithGoogle(
     accessToken: googleAuth.accessToken, 
     idToken: googleAuth.idToken, 
    ); 
     assert(user.email != null); 
     assert(user.displayName != null); 
     assert(!user.isAnonymous); 
     assert(await user.getToken() != null); 

     return user; 
    } 
    } 

更新3:

我的主要功能

void main() { 
     runApp(
      new MaterialApp(
     home: new SignIn(), 
     routes: <String, WidgetBuilder>{ 
      "/SignUp":(BuildContext context)=> new SignUp(), 
      "/Login": (BuildContext context)=> new SignIn(), 
      "/MyTabs": (BuildContext context)=> new MyTabs()}, 

)); 
} 

然后我签到包含一个谷歌按钮按下时:

onPressed:() { _testSignInWithGoogle(). //async returns FirebaseUser 
          whenComplete(()=>Navigator.of(context).pushNamed("/MyTabs") 
         ); 
         } 

和更新1的抽屉包括MyTabs内建立。

回答

2

有几种可能性。

第一:使用状态控件 重写INITSTATE方法是这样的:

class Test extends StatefulWidget { 
    @override 
    _TestState createState() => new _TestState(); 
} 

class _TestState extends State<Test> { 
    String _currentUserName; 

    @override 
    initState() { 
    super.initState(); 
    doAsyncStuff(); 
    } 

    doAsyncStuff() async { 
    var name = await _getCurrentUserName(); 
    setState(() { 
     this._currentUserName = name; 
    }); 
    } 


    @override 
    Widget build(BuildContext context) { 
    if (_currentUserName == null) 
     return new Container(); 
    return new Text(_currentUserName); 
    } 
} 

二:使用FutureBuilder部件 基本上,它是为那些不想使用状态的小部件谁的包装。它最终也是如此。 但是你将无法在其他地方重用你的未来。

class Test extends StatelessWidget { 
    @override 
    Widget build(BuildContext context) { 
    return new FutureBuilder(
     future: _getCurrentUserName(), 
     builder: (context, AsyncSnapshot<int> snapshot) { 
     if (snapshot.hasData) 
      return new Text(snapshot.data.toString()); 
     else 
      return new Container(); 
     }, 
    ); 
    } 
} 

说明: 你getCurrentUserName是异步的。 您不能直接将其与其他同步功能混合使用。 异步函数非常有用。但是如果你想使用它们,只要记住两件事:

在另一个异步函数,你可以var x = await myFuture,它将等到myFuture完成获得它的结果。

但是你不能在同步功能中使用await。您可以使用 myFuture.then(myFunction)myFuture.whenComplete(myFunction)。未来完成后将调用myFunction。他们都.then.whenComplete将通过未来的结果作为参数到您的myFunction

+0

我已经使用statefulwidget与状态,是正确的在同一个类来创建用于多种方法多种状态?或者我应该只更新现有的状态?我也尝试在一个单独的课堂上构建我的抽屉。这三个选项实际上工作正常,但在调试控制台上有一些错误,但首先我想了解如果您有多个状态,哪个是正确的方法? – aziza

+0

颤振是关于构图。如果你有一些与认证相同的东西,你可以考虑将该部分拆分成有状态的小部件。 类似于:Root> ...> MyAuth> ...> SomethingThatNeedAuth。 然后实现一个静态方法MyAuth.of(BuildContext)=> _MyAuthState。你应该很好。 – Darky

+0

我不确定我是否理解创建静态方法的部分。 – aziza

1

“如何正确实现认证”? 你绝对不应该这样做。你会有大量的代码重复。

组织层,如身份认证最理想的方式是这样的:

runApp(new Configuration.fromFile("confs.json", 
    child: new Authentification(
    child: new MaterialApp(
     home: new Column(
     children: <Widget>[ 
      new Text("Hello"), 
      new AuthentifiedBuilder(
      inRoles: [UserRole.admin], 
      builder: (context, user) { 
       return new Text(user.name); 
      } 
     ), 
     ], 
    ), 
    ), 
), 
)); 

然后,当你需要一个配置或构件内的当前用户,你可以这样做:

@override 
Widget build(BuildContext context) { 
    var user = Authentification.of(context).user; 
    var host = Configuration.of(context).host; 
    // do stuff with host and the user 
    return new Container(); 
} 

这样做有很多优点,所以没有理由不这样做。如“一次编码,到处使用”。或者具有一个通用值并覆盖特定窗口小部件的能力。 你会意识到很多Flutter小部件都遵循这个想法。 如导航器,脚手架,主题,...

但“如何做到这一点??” 这都要归功于BuildContext context参数。这提供了几个帮手来做到这一点。 对于为例,中Authentification.of(context)的代码将是以下几点:

class Authentification extends StatefulWidget { 
    final Widget child; 

    static AuthentificationData of(BuildContext context) { 
     final AuthentificationData auth = context.inheritFromWidgetOfExactType(AuthentificationData); 
     assert(auth != null); 
     return auth; 
    } 

    Authentification({this.child}); 
    @override 
    AuthentificationState createState() => new AuthentificationState(); 
} 
+0

我可以问你,当你说“你绝对不应该这样做”时,你指的是检查当前用户登录的方式,还是实现外部函数_testSignInWithGoogle()的整个想法来签名在用户中? – aziza

+1

这是关于“不要与苹果混合土豆”。一堂课,一份工作。 如果你不分割东西,你的应用程序开发过程中会遇到很多问题。如复制粘贴代码,这使得维护/调试变得困难。 另一个例子:如果你想添加酉测试,与模拟用户? 用我的例子,我可以实例化一个从“验证”类继承的“TestAuth”类。重写一些方法。一切都完成了。但是你 ?你必须重写所有内容。 – Darky