简体   繁体   中英

Can't use the "_auth.signOut()" if I move to another widget

I'm trying to build an app with flutter firebase, and I'm facing a problem. In the moment I have the auth done, The user do the login and he is sent to a "home" widget, where he can sign out, Then I add a "Drawer" in the "home" widget, where we can go to the "home" widget or into the "refeições" widget, if I click on "home" he goes to the "home" widget or if I click on the "refeições" he goes to the "refeições" widget and then I click on the "home" and he is sent to the "home" widget, the button "Sign out" doesn't work anymore!

This is my code:

main:

import 'package:flutter/material.dart';
import 'package:projeto_final/models/user.dart';
import 'package:projeto_final/screens/wrapper.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:projeto_final/services/auth.dart';
import 'package:provider/provider.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});


  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return StreamProvider<Userr?>.value(
      initialData: null,
      value: AuthServices().user, 
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        home:
            Wrapper(),
      ),
    );
  }
}

wrapper:

import 'package:flutter/material.dart';
import 'package:projeto_final/models/user.dart';
import 'package:projeto_final/screens/authenticate/authenticate.dart';
import 'package:projeto_final/screens/home/home.dart';
import 'package:provider/provider.dart';

class Wrapper extends StatelessWidget {
  const Wrapper({super.key});

  @override
  Widget build(BuildContext context) {
    final user = Provider.of<Userr?>(context);
    if (user == null) {
      return Authenticate();
    } else {
      return Home();
    }
  }
}

home:

import 'package:flutter/material.dart';
import 'package:projeto_final/models/user.dart';
import 'package:projeto_final/services/auth.dart';
import 'package:projeto_final/screens/home/refeicoes.dart';
import 'package:projeto_final/screens/home/navigatorDrawer.dart';
import 'package:provider/provider.dart';

class Home extends StatefulWidget {
  const Home({super.key});

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  // instancia da auth
  final AuthServices _auth = AuthServices();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      drawer: const NavigationDrawer(),
      backgroundColor: Colors.brown[50],
      appBar: AppBar(
        title: Text('Homre'),
        backgroundColor: Colors.brown[400],
        elevation: 0.0,
        actions: <Widget>[
          TextButton.icon(
            style: TextButton.styleFrom(primary: Colors.black),
            icon: Icon(
              Icons.logout,
              color: Colors.white,
            ),
            label: Text(''),
            onPressed: () async {
              print("sigout"); // this apper on the Debug Cosole
              await _auth.signout();
            },
          ),
        ],
      ),
    );
  }
}

navigationDrawer:

import 'package:flutter/material.dart';
import 'package:projeto_final/models/user.dart';
import 'package:projeto_final/screens/home/home.dart';
import 'package:projeto_final/screens/home/perfil.dart';
import 'package:projeto_final/screens/home/refeicoes.dart';
import 'package:provider/provider.dart';

class NavigationDrawer extends StatelessWidget {
  const NavigationDrawer({super.key});

  @override
  Widget build(BuildContext context) {
    //final user = Provider.of<Userr?>(context);
    return Drawer(
      child: SingleChildScrollView(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            buildHeader(context),
            buildMenuItem(context),
          ],
        ),
      ),
    );
  }

// Infomações da pessoa
  Widget buildHeader(BuildContext context) => Material(
        color: Colors.blue.shade700,
        child: InkWell(
          onTap: () {
            Navigator.pop(context);
            Navigator.of(context).push(MaterialPageRoute(
              builder: (context) => const Perfil(),
            ));
          },
          child: Container(
            padding: EdgeInsets.only(
              top: 24 + MediaQuery.of(context).padding.top,
              bottom: 24,
            ),
            child: Column(
              children: <Widget>[
                CircleAvatar(
                  radius: 52,
                  backgroundImage: NetworkImage(
                      'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTpnpGpHRvo3bnHH-bUT_h5Y9Ao31CXetXjJMZ4HGcDasQ-oIc-VptCHRNzF3eeM5vOsQA&usqp=CAU'),
                ),
                SizedBox(height: 12),
                Text(
                  'base de dados',
                  style: TextStyle(fontSize: 28, color: Colors.white),
                ),
                Text(
                  'base de dados@gmail.om',
                  style: TextStyle(fontSize: 16, color: Colors.white),
                )
              ],
            ),
          ),
        ),
      );

  Widget buildMenuItem(BuildContext context) => Container(
        padding: const EdgeInsets.all(24), // horizontal
        child: Wrap(
          runSpacing: 5, // vertical spacing
          children: [
            const Divider(color: Colors.black),
            ListTile(
              leading: const Icon(Icons.home_outlined),
              title: const Text('Home'),
              onTap: () {
                Navigator.of(context).pushReplacement(
                  MaterialPageRoute(
                    builder: (context) => Home(),
                  ),
                );
              },
            ),
            const Divider(color: Colors.black),
            ListTile(
              leading: const Icon(Icons.food_bank_outlined),
              title: const Text('Refeições'),
              onTap: () {
                Navigator.pop(context);
                Navigator.of(context).push(MaterialPageRoute(
                  builder: (context) => const Refeicoes(),
                ));
              },
            ),
            const Divider(color: Colors.black),
          ],
        ),
      );
}

refeicoes:

import 'package:flutter/material.dart';
import 'package:projeto_final/screens/home/home.dart';
import 'package:projeto_final/screens/home/navigatorDrawer.dart';

class Refeicoes extends StatefulWidget {
  const Refeicoes({super.key});

  @override
  State<Refeicoes> createState() => _RefeicoesState();
}

class _RefeicoesState extends State<Refeicoes> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      drawer: NavigationDrawer(),
      appBar: AppBar(
        title: Text('Refeições'),
      ),
    );
  }
}

auth:

import 'package:firebase_auth/firebase_auth.dart';
import 'package:projeto_final/models/user.dart';

class AuthServices {
  // definir todos os metodos que vao comunicar com a firebase auth

  final FirebaseAuth _auth = FirebaseAuth.instance;

  // create a USER obj based on firebaseUser
  Userr? _userFromFireBaseUser(User? user) {
    //return Userr(uid: user.uid);
    return user != null
        ? Userr(
            uid: user.uid,
          )
        : null;
  }

  //auth change user stream
  // função que devolve null ou entao o iud da pessoa que acabou de fazer regustar/sign
  // função serve para ir para "home" ou entao para o "sign in"
  Stream<Userr?> get user {
    return _auth
        .authStateChanges()
        .map((User? user) => _userFromFireBaseUser(user));
    //.map(_userFromFirebaseUser);
  }

  //sign in anon
  Future signInAnon() async {
    try {
      UserCredential result = await _auth.signInAnonymously();
      User? user = result.user;
      return _userFromFireBaseUser(user);
    } catch (e) {
      print(e.toString());
      return null;
    }
  }

  // sign in with email and pass
  Future SignInWithEmailPassword(String email, String password) async {
    try {
      UserCredential result = await _auth.signInWithEmailAndPassword(
          email: email, password: password);
      User? user = result.user;
      return _userFromFireBaseUser(user);
    } catch (e) {
      print(e.toString());
      return null;
    }
  }

  // register with email and pass
  Future registerWithEmailPassword(String email, String password) async {
    try {
      UserCredential result = await _auth.createUserWithEmailAndPassword(
          email: email, password: password);
      User? user = result.user;
      return _userFromFireBaseUser(user);
    } catch (e) {
      print(e.toString());
      return null;
    }
  }

  //sign out
  Future signout() async {
    try {
      return await _auth.signOut();
    } catch (e) {
      print(e.toString());
      return null;
    }
  }
}

user.dart

class Userr {
  final String uid;

  Userr({required this.uid});
}

I tried to put a

print(user!.uid)

when I click on the button to "signout" and the Debug Console say

════════ Exception caught by widgets library ═══════════════════════════════════
Null check operator used on a null value
The relevant error-causing widget was
Home
lib/…/home/navigatorDrawer.dart:76
════════════════════════════════════════════════════════════════════════════════ 

So I think the problem is when I move from one widget to another I m not passing data about the "user"

You can try logging out using Firebase instance.

FirebaseAuth.instance.signOut();

This is probably due to stacking. I will advice you create a global AppBar that can be modified for every screen you want to call it at. This method will require creation of a custom app bar StateFulWidget.

I also notice some issues with "FirebaseAuth.instance.signOut();"these days. A work around I will suggest is to use shared preferences to store user ID and validate ifLogin() with shared preferences. While with the logOut() function, you first delete the user ID in the shared preferences and Navigate back to the login screen while in same logOut() function, use future delay to delay the FirebaseAuth.instance.signOut() call for some seconds.

  Future<void> signOut() async {
    final prefs = await SharedPreferences.getInstance();
    prefs.remove('userID');

    Future.delayed(const Duration(seconds: 5), () => _auth.signOut());
  }

Also try to use pushReplacement on your Navigator at the right location. This will reduce your screen stack layers and give better performance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM