首页 > 解决方案 > Firebase signOut() 问题(颤振)

问题描述

我有一个使用 firebase 的应用程序,我在 RootPage 中处理登录或登录,然后它传递到我的 FirstPage,如果我直接注销而不从 FirstPage 走任何路线,它运行良好并引导我进入我的 RootPage 未签名版本,但如果我去任何从我的 FirstPage 路由并返回那里然后尝试签出它只是给出以下错误:

D/FirebaseAuth(10720): Notifying id token listeners about a sign-out event.
D/FirebaseAuth(10720): Notifying auth state listeners about a sign-out event.
I/flutter (10720): NoSuchMethodError: The method 'call' was called on null.
I/flutter (10720): Receiver: null
I/flutter (10720): Tried calling: call()

我有一个 movetohome 功能,可以从任何页面返回我的 FirstPage,我认为它缺少一些东西,我的功能如下;

_moveToHome(BuildContext context) {
    Route route = MaterialPageRoute(builder: (context) => MyFirstPage(auth: FirebaseAuth.instance,userId: userId,));
    Navigator.push(context, route);
}

您可以在我的页面中找到与 firebase 相关的部分;

主要飞镖:

 void main() => runApp(new MyApp());

 class MyApp extends StatelessWidget {
      const MyApp();
      @override
      Widget build(BuildContext context) {
        return DynamicTheme(
            defaultBrightness: Brightness.light,
            data: (brightness) => ThemeData(
              pageTransitionsTheme: PageTransitionsTheme(
                  builders: {
                    TargetPlatform.android: CupertinoPageTransitionsBuilder(),
                    TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
                  }
              ),
              primarySwatch: Colors.blueGrey,
              accentColor: Colors.blueGrey,
              fontFamily: 'AvenirNext',
              brightness: brightness,
            ),

            themedWidgetBuilder: (context, theme) {
              return MaterialApp(
                theme: theme,
                home: new RootPage(auth: new Auth()),
                routes: <String, WidgetBuilder>{
                  MyFirstPage.routeName: (context) => new MyFirstPage(auth: new Auth()),
                  DetailPage.routeName: (context) => new DetailPage(auth: new Auth()),
                  GenrePage.routeName: (context) => new GenrePage(auth: new Auth())
                },
              );
            });
      }
    }

根页:

import 'package:flutter/material.dart';
import 'package:randommoviefinal/screens/login_singup_page.dart';
import 'package:randommoviefinal/services/authentication.dart';
import 'package:randommoviefinal/screens/HomePage.dart';

enum AuthStatus {
  NOT_DETERMINED,
  NOT_LOGGED_IN,
  LOGGED_IN,
}

class RootPage extends StatefulWidget {
  RootPage({this.auth});

  final BaseAuth auth;

  @override
  State<StatefulWidget> createState() => new _RootPageState();
}

class _RootPageState extends State<RootPage> {
  AuthStatus authStatus = AuthStatus.NOT_DETERMINED;
  String _userId = "";

  @override
  void initState() {
    super.initState();
    widget.auth.getCurrentUser().then((user) {
      setState(() {
        if (user != null) {
          _userId = user?.uid;
        }
        authStatus =
        user?.uid == null ? AuthStatus.NOT_LOGGED_IN : AuthStatus.LOGGED_IN;
      });
    });
  }

  void loginCallback() {
    widget.auth.getCurrentUser().then((user) {
      setState(() {
        _userId = user.uid.toString();
      });
    });
    setState(() {
      authStatus = AuthStatus.LOGGED_IN;
    });
  }

  void logoutCallback() {
    setState(() {
      authStatus = AuthStatus.NOT_LOGGED_IN;
      _userId = "";
    });
  }

  Widget buildWaitingScreen() {
    return Scaffold(
      body: Container(
        alignment: Alignment.center,
        child: CircularProgressIndicator(),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    switch (authStatus) {
      case AuthStatus.NOT_DETERMINED:
        return buildWaitingScreen();
        break;
      case AuthStatus.NOT_LOGGED_IN:
        return new LoginSignupPage(
          auth: widget.auth,
          loginCallback: loginCallback,
        );
        break;
      case AuthStatus.LOGGED_IN:
        if (_userId.length > 0 && _userId != null) {
          return new MyFirstPage(
            userId: _userId,
            auth: widget.auth,
            logoutCallback: logoutCallback,
          );
        } else
          return buildWaitingScreen();
        break;
      default:
        return buildWaitingScreen();
    }
  }
}

我的第一页:

class MyFirstPage extends StatefulWidget {
  MyFirstPage({Key key, this.auth, this.userId, this.logoutCallback})
      : super(key: key);

  final auth;
  final VoidCallback logoutCallback;
  final String userId;

  static String routeName = "/MyFirstPage";

  @override
  _MyFirstPageState createState() => new _MyFirstPageState();
}

class _MyFirstPageState extends State<MyFirstPage> {

  String userId;
  List<Movies> _moviesList;

  final FirebaseDatabase _database = FirebaseDatabase.instance;
  final GlobalKey<FormState> formKey = GlobalKey<FormState>();
  Query _moviesQuery;
  StreamSubscription<Event> _onMoviesAddedSubscription;
  StreamSubscription<Event> _onMoviesChangedSubscription;

 @override
  void initState() {
    // TODO: implement initState
    super.initState();

    _moviesList = new List();
    _moviesQuery = _database
        .reference()
        .child("movies")
        .orderByChild("userId")
        .equalTo(widget.userId);
    _onMoviesAddedSubscription = _moviesQuery.onChildAdded.listen(onEntryAdded);
    _onMoviesChangedSubscription =
        _moviesQuery.onChildChanged.listen(onEntryChanged);

  }

  void dispose() {
    _onMoviesAddedSubscription.cancel();
    _onMoviesChangedSubscription.cancel();
    super.dispose();
  }

  onEntryChanged(Event event) {
    var oldEntry = _moviesList.singleWhere((entry) {
      return entry.key == event.snapshot.key;
    });

    setState(() {
      _moviesList[_moviesList.indexOf(oldEntry)] =
          Movies.fromSnapshot(event.snapshot);
    });
  }

  onEntryAdded(Event event) {
    setState(() {
      _moviesList.add(Movies.fromSnapshot(event.snapshot));
    });
  }

  signOut() async {
    try {
      await widget.auth.signOut();
      widget.logoutCallback();
    } catch (e) {
      print(e);
    }
  }

  updateMovies(Movies movies) {
    //Toggle completed
    movies.watched = !movies.watched;
    if (movies != null) {
      _database.reference().child("movies").child(movies.key).set(movies.toJson());
    }
  }

  deleteMovies(String moviesId, int index) {
    _database.reference().child("movies").child(moviesId).remove().then((_) {
      print("Delete $moviesId successful");
      setState(() {
        _moviesList.removeAt(index);
      });
    });
  }

我的另一个页面例如:

class DetailPage extends StatefulWidget {
  MovieDetailPage({Key key, this.title, this.auth, this.userId})
      : super(key: key);

  final auth;
  final String userId;
  static String routeName = "/MyHomePage";
  final String title;

  @override
  _DetailPageState createState() => _DetailPageState();}

class _DetailPageState extends State<MovieDetailPage> {

  String userId;
  final FirebaseDatabase _database = FirebaseDatabase.instance;
  final GlobalKey<FormState> formKey = GlobalKey<FormState>();
  StreamSubscription<Event> _onMoviesAddedSubscription;
  StreamSubscription<Event> _onMoviesChangedSubscription;
  Query _moviesQuery;
  List<Movies> _moviesList;

  _moveToHome(BuildContext context) {
    Route route = MaterialPageRoute(builder: (context) => MyFirstPage(auth: FirebaseAuth.instance,userId: userId,));
    Navigator.push(context, route);}

@override
  void initState() {
    // TODO: implement initState
    super.initState();
    _moviesList = new List();
    _moviesQuery = _database
        .reference()
        .child("movies")
        .orderByChild("userId")
        .equalTo(widget.userId);
    _onMoviesAddedSubscription = _moviesQuery.onChildAdded.listen(onEntryAdded);
    _onMoviesChangedSubscription =
        _moviesQuery.onChildChanged.listen(onEntryChanged);
    widget.auth.getCurrentUser().then((user) {
      if (user != null) {
        userId = user?.uid;
      }});
  }

  void dispose() {
    _onMoviesAddedSubscription.cancel();
    _onMoviesChangedSubscription.cancel();
    super.dispose();
  }

  onEntryChanged(Event event) {
    var oldEntry = _moviesList.singleWhere((entry) {
      return entry.key == event.snapshot.key;
    });

    setState(() {
      _moviesList[_moviesList.indexOf(oldEntry)] =
          Movies.fromSnapshot(event.snapshot);
    });
  }

  onEntryAdded(Event event) {
    setState(() {
      _moviesList.add(Movies.fromSnapshot(event.snapshot));
    });
  }

  updateMovies(Movies movies) {
    //Toggle completed
    movies.watched = !movies.watched;
    if (movies != null) {
      _database.reference().child("movies").child(movies.key).set(movies.toJson());
    }
  }

  deleteMovies(String moviesId, int index) {
    _database.reference().child("movies").child(moviesId).remove().then((_) {
      print("Delete $moviesId successful");
      setState(() {
        _moviesList.removeAt(index);
      });
    });
  }

...
IconButton(
                            icon: Icon(Icons.home),
                            iconSize: 35,
                            onPressed: () {
                              _moveToHome(context);
                            },
                          ),

...

和 authentication.dart

import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';

abstract class BaseAuth {
  Future<String> signIn(String email, String password);

  Future<String> signUp(String email, String password);

  Future<FirebaseUser> getCurrentUser();

  Future<void> sendEmailVerification();

  Future<void> signOut();

  Future<bool> isEmailVerified();
}

class Auth implements BaseAuth {
  final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;

  Future<String> signIn(String email, String password) async {
    AuthResult result = await _firebaseAuth.signInWithEmailAndPassword(
        email: email, password: password);
    FirebaseUser user = result.user;
    return user.uid;
  }

  Future<String> signUp(String email, String password) async {
    AuthResult result = await _firebaseAuth.createUserWithEmailAndPassword(
        email: email, password: password);
    FirebaseUser user = result.user;
    return user.uid;
  }

  Future<FirebaseUser> getCurrentUser() async {
    FirebaseUser user = await _firebaseAuth.currentUser();
    return user;
  }

  Future<void> signOut() async {
    return _firebaseAuth.signOut();
  }

  Future<void> sendEmailVerification() async {
    FirebaseUser user = await _firebaseAuth.currentUser();
    user.sendEmailVerification();
  }

  Future<bool> isEmailVerified() async {
    FirebaseUser user = await _firebaseAuth.currentUser();
    return user.isEmailVerified;
  }
}

标签: firebaseflutterfirebase-authentication

解决方案


我认为FirebaseAuth当您离开主页尝试移动时正在失去当前用户

 final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
class Auth implements BaseAuth {
 //Rest of class

以这种方式在你的类之外,它具有全局范围,只需确保它不在它上面的抽象类中


推荐阅读