2017-08-22 74 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