0

I have an app using firebase, I handle sign in or log in in RootPage then it passes to my FirstPage, if I directly logout without go any route from FirstPage it is working well and leading me to my RootPage unsigned version but if I go any route from my FirstPage and go back there then try to signOut it just give below error:

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()

I have a movetohome function to go back my FirstPage from any page and I think there is something missing at it, my function is below;

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

and you can find firebase related parts of my pages;

main.dart:

 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())
                },
              );
            });
      }
    }

RootPage:

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();
    }
  }
}

MyFirstPage:

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);
      });
    });
  }

My another page for example:

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);
                            },
                          ),

...

and 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;
  }
}

1 Answer 1

1

I think FirebaseAuth is losing current user when you leave your home page try moving

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

to right outside your class this way it has global scope just make sure it not in the abstract class that's right above it

Sign up to request clarification or add additional context in comments.

2 Comments

Tried that now but still same. I think your point is correct I'm loosing current user info somehow that's why I have to pass my userid to any page but I couldn't figured out how..
I made it and you are right I was losing current user while routing, I rearranged all pages then problem solved, thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.