Provider.of 总是返回 null Flutter
Posted
技术标签:
【中文标题】Provider.of 总是返回 null Flutter【英文标题】:Provider.of always returning null Flutter 【发布时间】:2021-02-21 06:44:22 【问题描述】:我有一个提供程序对象,它上周一直在工作,直到我这样做了
flutter channel stable
flutter upgrade
现在,它总是返回 null。
问题出现在我的启动页面上。以下是页面内容:
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:boots/helper/enum.dart';
import 'package:boots/helper/theme.dart';
import 'package:boots/page/Auth/selectAuthMethod.dart';
import 'package:boots/page/homePage.dart';
import 'package:boots/state/authState.dart';
import 'package:boots/widgets/customWidgets.dart';
import 'package:provider/provider.dart';
class SplashPage extends StatefulWidget
SplashPage(Key key) : super(key: key);
@override
_SplashPageState createState() => _SplashPageState();
class _SplashPageState extends State<SplashPage>
@override
void initState()
WidgetsBinding.instance.addPostFrameCallback((_)
timer();
);
super.initState();
void timer() async
Future.delayed(Duration(seconds: 1)).then((_)
var state = Provider.of<AuthState>(context, listen: false);
state.getCurrentUser();
);
Widget _body()
var height = 150.0;
return Container(
height: fullHeight(context),
width: fullWidth(context),
child: Container(
height: height,
width: height,
alignment: Alignment.center,
child: Container(
padding: EdgeInsets.all(50),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(10),
),
),
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Platform.isios
? CupertinoActivityIndicator(
radius: 35,
)
: CircularProgressIndicator(
strokeWidth: 2,
),
Image.asset(
'assets/images/icon-480.png',
height: 30,
width: 30,
)
],
),
),
),
);
@override
Widget build(BuildContext context)
var state = Provider.of<AuthState>(context);
return Scaffold(
backgroundColor: TwitterColor.white,
body: state.authStatus == AuthStatus.NOT_DETERMINED
? _body()
: state.authStatus == AuthStatus.NOT_LOGGED_IN
? WelcomePage()
: HomePage(),
);
这里的罪魁祸首是函数:
void timer() async
Future.delayed(Duration(seconds: 1)).then((_)
var state = Provider.of<AuthState>(context, listen: false);
state.getCurrentUser();
);
我的 main.dart 是我为 AuthState 设置 ChangeNotifierProvider 的地方,看起来像:
import 'package:boots/blocs/place_bloc.dart';
import 'package:boots/helper/locator.dart';
import 'package:boots/state/communitiesState.dart';
import 'package:boots/state/mapState.dart';
import 'package:flutter/material.dart';
import 'package:boots/helper/theme.dart';
import 'package:boots/state/searchState.dart';
import 'package:boots/state/nearbyState.dart';
import 'package:flutter/services.dart';
import 'helper/routes.dart';
import 'state/appState.dart';
import 'package:provider/provider.dart';
import 'state/authState.dart';
import 'state/chats/chatState.dart';
import 'state/feedState.dart';
import 'package:google_fonts/google_fonts.dart';
import 'state/notificationState.dart';
void main()
setupLocator();
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(statusBarColor: AppColor.primary));
return MultiProvider(
providers: [
ChangeNotifierProvider<AppState>(create: (_) => AppState()),
ChangeNotifierProvider<AuthState>(create: (_) => AuthState()),
ChangeNotifierProvider<FeedState>(create: (_) => FeedState()),
ChangeNotifierProvider<ChatState>(create: (_) => ChatState()),
ChangeNotifierProvider<SearchState>(create: (_) => SearchState()),
ChangeNotifierProvider<NotificationState>(
create: (_) => NotificationState()),
ChangeNotifierProvider<MapState>(create: (_) => MapState()),
ChangeNotifierProvider<CommunitiesState>(
create: (_) => CommunitiesState()),
ChangeNotifierProvider<NearbyState>(create: (_) => NearbyState()),
ChangeNotifierProvider<PlaceBloc>(create: (_) => PlaceBloc()),
],
child: MaterialApp(
title: 'Boots',
theme: AppTheme.apptheme.copyWith(
textTheme: GoogleFonts.muliTextTheme(
Theme.of(context).textTheme,
),
),
debugShowCheckedModeBanner: false,
routes: Routes.route(), // goes to splash.dart
onGenerateRoute: (settings) => Routes.onGenerateRoute(settings),
onUnknownRoute: (settings) => Routes.onUnknownRoute(settings),
),
);
最后,我的 AuthState 类看起来像:
import 'dart:io';
import 'package:firebase_auth/firebase_auth.dart' as firebaseauth;
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:boots/helper/enum.dart';
import 'package:boots/helper/utility.dart';
import 'package:boots/model/user.dart';
import 'package:boots/widgets/customWidgets.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:path/path.dart' as Path;
import 'appState.dart';
import 'package:firebase_database/firebase_database.dart' as dabase;
class AuthState extends AppState
AuthStatus authStatus = AuthStatus.NOT_DETERMINED;
bool isSignInWithGoogle = false;
firebaseauth.User user;
String userId;
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
final firebaseauth.FirebaseAuth _firebaseAuth =
firebaseauth.FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn();
dabase.Query _profileQuery;
List<User> _profileUserModelList;
User _userModel;
User get userModel => _userModel;
User get profileUserModel
if (_profileUserModelList != null && _profileUserModelList.length > 0)
return _profileUserModelList.last;
else
return null;
void removeLastUser()
_profileUserModelList.removeLast();
/// Logout from device
void logoutCallback()
authStatus = AuthStatus.NOT_LOGGED_IN;
userId = '';
_userModel = null;
user = null;
_profileUserModelList = null;
if (isSignInWithGoogle)
_googleSignIn.signOut();
logEvent('google_logout');
_firebaseAuth.signOut();
notifyListeners();
/// Alter select auth method, login and sign up page
void openSignUpPage()
authStatus = AuthStatus.NOT_LOGGED_IN;
userId = '';
notifyListeners();
databaseInit()
try
if (_profileQuery == null)
_profileQuery = kDatabase.child("profile").child(user.uid);
_profileQuery.onValue.listen(_onProfileChanged);
catch (error)
cprint(error, errorIn: 'databaseInit');
/// Verify user's credentials for login
Future<String> signIn(String email, String password,
GlobalKey<ScaffoldState> scaffoldKey) async
try
loading = true;
var result = await _firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
user = result.user;
userId = user.uid;
return user.uid;
catch (error)
loading = false;
cprint(error, errorIn: 'signIn');
kAnalytics.logLogin(loginMethod: 'email_login');
customSnackBar(scaffoldKey, error.message);
// logoutCallback();
return null;
/// Create user from `google login`
/// If user is new then it create a new user
/// If user is old then it just `authenticate` user and return firebase user data
Future<firebaseauth.User> handleGoogleSignIn() async
try
/// Record log in firebase kAnalytics about Google login
kAnalytics.logLogin(loginMethod: 'google_login');
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
if (googleUser == null)
throw Exception('Google login cancelled by user');
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final firebaseauth.AuthCredential credential =
firebaseauth.GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
user = (await _firebaseAuth.signInWithCredential(credential)).user;
authStatus = AuthStatus.LOGGED_IN;
userId = user.uid;
isSignInWithGoogle = true;
createUserFromGoogleSignIn(user);
notifyListeners();
return user;
on PlatformException catch (error)
user = null;
authStatus = AuthStatus.NOT_LOGGED_IN;
cprint(error, errorIn: 'handleGoogleSignIn');
return null;
on Exception catch (error)
user = null;
authStatus = AuthStatus.NOT_LOGGED_IN;
cprint(error, errorIn: 'handleGoogleSignIn');
return null;
catch (error)
user = null;
authStatus = AuthStatus.NOT_LOGGED_IN;
cprint(error, errorIn: 'handleGoogleSignIn');
return null;
/// Create user profile from google login
createUserFromGoogleSignIn(firebaseauth.User user)
var diff = DateTime.now().difference(user.metadata.creationTime);
// Check if user is new or old
// If user is new then add new user to firebase realtime kDatabase
if (diff < Duration(seconds: 15))
User model = User(
bio: 'Edit profile to update bio',
dob: DateTime(1950, DateTime.now().month, DateTime.now().day + 3)
.toString(),
location: 'Somewhere in universe',
profilePic: user.photoURL,
displayName: user.displayName,
email: user.email,
key: user.uid,
userId: user.uid,
contact: user.phoneNumber,
isVerified: user.emailVerified,
);
createUser(model, newUser: true);
else
cprint('Last login at: $user.metadata.lastSignInTime');
/// Create new user's profile in db
Future<String> signUp(User userModel,
GlobalKey<ScaffoldState> scaffoldKey, String password) async
try
loading = true;
var result = await _firebaseAuth.createUserWithEmailAndPassword(
email: userModel.email,
password: password,
);
user = result.user;
authStatus = AuthStatus.LOGGED_IN;
kAnalytics.logSignUp(signUpMethod: 'register');
await result.user.updateProfile(
displayName: userModel.displayName,
photoURL: userModel.profilePic,
);
_userModel = userModel;
_userModel.key = user.uid;
_userModel.userId = user.uid;
createUser(_userModel, newUser: true);
return user.uid;
catch (error)
loading = false;
cprint(error, errorIn: 'signUp');
customSnackBar(scaffoldKey, error.message);
return null;
/// `Create` and `Update` user
/// IF `newUser` is true new user is created
/// Else existing user will update with new values
createUser(User user, bool newUser = false)
if (newUser)
// Create username by the combination of name and id
user.userName = getUserName(email: user.email);
kAnalytics.logEvent(name: 'create_newUser');
// Time at which user is created
user.createdAt = DateTime.now().toUtc().toString();
kDatabase.child('profile').child(user.userId).set(user.toJsonUpdate());
_userModel = user;
if (_profileUserModelList != null)
_profileUserModelList.last = _userModel;
loading = false;
/// Fetch current user profile
Future<firebaseauth.User> getCurrentUser() async
try
loading = true;
logEvent('get_currentUSer');
user = _firebaseAuth != null ? _firebaseAuth.currentUser : null;
if (user != null)
authStatus = AuthStatus.LOGGED_IN;
userId = user.uid;
getProfileUser();
else
authStatus = AuthStatus.NOT_LOGGED_IN;
loading = false;
return user;
catch (error)
loading = false;
cprint(error, errorIn: 'getCurrentUser');
authStatus = AuthStatus.NOT_LOGGED_IN;
return null;
/// Reload user to get refresh user data
reloadUser() async
await user.reload();
user = _firebaseAuth.currentUser;
if (user.emailVerified)
userModel.isVerified = true;
// If user verifed his email
// Update user in firebase realtime kDatabase
createUser(userModel);
cprint('User email verification complete');
logEvent('email_verification_complete',
parameter: userModel.userName: user.email);
/// Send email verification link to email2
Future<void> sendEmailVerification(
GlobalKey<ScaffoldState> scaffoldKey) async
firebaseauth.User user = _firebaseAuth.currentUser;
user.sendEmailVerification().then((_)
logEvent('email_verifcation_sent',
parameter: userModel.displayName: user.email);
customSnackBar(
scaffoldKey,
'An email verification link is send to your email.',
);
).catchError((error)
cprint(error.message, errorIn: 'sendEmailVerification');
logEvent('email_verifcation_block',
parameter: userModel.displayName: user.email);
customSnackBar(
scaffoldKey,
error.message,
);
);
/// Check if user's email is verified
Future<bool> isEmailVerified() async
firebaseauth.User user = _firebaseAuth.currentUser;
return user.emailVerified;
/// Send password reset link to email
Future<void> forgetPassword(String email,
GlobalKey<ScaffoldState> scaffoldKey) async
try
await _firebaseAuth.sendPasswordResetEmail(email: email).then((value)
customSnackBar(scaffoldKey,
'A reset password link is sent yo your mail.You can reset your password from there');
logEvent('forgot+password');
).catchError((error)
cprint(error.message);
return false;
);
catch (error)
customSnackBar(scaffoldKey, error.message);
return Future.value(false);
/// `Update user` profile
Future<void> updateUserProfile(User userModel, File image) async
try
if (image == null)
createUser(userModel);
else
Reference storageReference = FirebaseStorage.instance
.ref()
.child('user/profile/$Path.basename(image.path)');
UploadTask uploadTask = storageReference.putFile(image);
await uploadTask.then((value)
storageReference.getDownloadURL().then((fileURL) async
print(fileURL);
await user.updateProfile(
displayName: userModel?.displayName ?? user.displayName,
photoURL: fileURL,
);
if (userModel != null)
userModel.profilePic = fileURL;
createUser(userModel);
else
_userModel.profilePic = fileURL;
createUser(_userModel);
);
);
logEvent('update_user');
catch (error)
cprint(error, errorIn: 'updateUserProfile');
/// `Fetch` user `detail` whoose userId is passed
Future<User> getuserDetail(String userId) async
User user;
var snapshot = await kDatabase.child('profile').child(userId).once();
if (snapshot.value != null)
var map = snapshot.value;
user = User.fromJson(map);
user.key = snapshot.key;
return user;
else
return null;
/// Fetch user profile
/// If `userProfileId` is null then logged in user's profile will fetched
getProfileUser(String userProfileId)
try
loading = true;
if (_profileUserModelList == null)
_profileUserModelList = [];
userProfileId = userProfileId == null ? user.uid : userProfileId;
kDatabase
.child("profile")
.child(userProfileId)
.once()
.then((DataSnapshot snapshot)
if (snapshot.value != null)
var map = snapshot.value;
if (map != null)
_profileUserModelList.add(User.fromJson(map));
if (userProfileId == user.uid)
_userModel = _profileUserModelList.last;
_userModel.isVerified = user.emailVerified;
if (!user.emailVerified)
// Check if logged in user verified his email address or not
reloadUser();
if (_userModel.fcmToken == null)
updateFCMToken();
logEvent('get_profile');
loading = false;
);
catch (error)
loading = false;
cprint(error, errorIn: 'getProfileUser');
/// if firebase token not available in profile
/// Then get token from firebase and save it to profile
/// When someone sends you a message FCM token is used
void updateFCMToken()
if (_userModel == null)
return;
getProfileUser();
_firebaseMessaging.getToken().then((String token)
assert(token != null);
_userModel.fcmToken = token;
createUser(_userModel);
);
/// Follow / Unfollow user
///
/// If `removeFollower` is true then remove user from follower list
///
/// If `removeFollower` is false then add user to follower list
followUser(bool removeFollower = false)
/// `userModel` is user who is looged-in app.
/// `profileUserModel` is user whoose profile is open in app.
try
if (removeFollower)
/// If logged-in user `alredy follow `profile user then
/// 1.Remove logged-in user from profile user's `follower` list
/// 2.Remove profile user from logged-in user's `following` list
profileUserModel.followersList.remove(userModel.userId);
/// Remove profile user from logged-in user's following list
userModel.followingList.remove(profileUserModel.userId);
cprint('user removed from following list', event: 'remove_follow');
else
/// if logged in user is `not following` profile user then
/// 1.Add logged in user to profile user's `follower` list
/// 2. Add profile user to logged in user's `following` list
if (profileUserModel.followersList == null)
profileUserModel.followersList = [];
profileUserModel.followersList.add(userModel.userId);
// Adding profile user to logged-in user's following list
if (userModel.followingList == null)
userModel.followingList = [];
userModel.followingList.add(profileUserModel.userId);
// update profile user's user follower count
profileUserModel.followers = profileUserModel.followersList.length;
// update logged-in user's following count
userModel.following = userModel.followingList.length;
kDatabase
.child('profile')
.child(profileUserModel.userId)
.child('followerList')
.set(profileUserModel.followersList);
kDatabase
.child('profile')
.child(userModel.userId)
.child('followingList')
.set(userModel.followingList);
cprint('user added to following list', event: 'add_follow');
notifyListeners();
catch (error)
cprint(error, errorIn: 'followUser');
/// Trigger when logged-in user's profile change or updated
/// Firebase event callback for profile update
void _onProfileChanged(Event event)
if (event.snapshot != null)
final updatedUser = User.fromJson(event.snapshot.value);
if (updatedUser.userId == user.uid)
_userModel = updatedUser;
cprint('User Updated');
notifyListeners();
这些是我做的时候得到的日志
flutter clean
紧随其后
flutter run --release
日志:
I/flutter (13941):
E/flutter (13941): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: NoSuchMethodError: The method 'getCurrentUser' was called on null.
E/flutter (13941): Receiver: null
E/flutter (13941): Tried calling: getCurrentUser()
E/flutter (13941): #0 _SplashPageState.timer.<anonymous closure> (package:boots/page/common/splash.dart:31)
E/flutter (13941): #1 _rootRunUnary (dart:async/zone.dart:1198)
E/flutter (13941): #2 _CustomZone.runUnary (dart:async/zone.dart:1100)
E/flutter (13941): #3 _FutureListener.handleValue (dart:async/future_impl.dart:143)
E/flutter (13941): #4 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:696)
E/flutter (13941): #5 Future._propagateToListeners (dart:async/future_impl.dart:725)
E/flutter (13941): #6 Future._complete (dart:async/future_impl.dart:519)
E/flutter (13941): #7 new Future.delayed.<anonymous closure> (dart:async/future.dart:323)
E/flutter (13941): #8 _rootRun (dart:async/zone.dart:1182)
E/flutter (13941): #9 _CustomZone.run (dart:async/zone.dart:1093)
E/flutter (13941): #10 _CustomZone.runGuarded (dart:async/zone.dart:997)
E/flutter (13941): #11 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1037)
E/flutter (13941): #12 _rootRun (dart:async/zone.dart:1190)
E/flutter (13941): #13 _CustomZone.run (dart:async/zone.dart:1093)
E/flutter (13941): #14 _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:1021)
E/flutter (13941): #15 TickerFuture.whenCompleteOrCancel.thunk (package:flutter/src/scheduler/ticker.dart:399)
E/flutter (13941): #16 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:397)
E/flutter (13941): #17 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:428)
E/flutter (13941): #18 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168)
E/flutter (13941):
我想纠正这个问题,因为我的应用程序因此根本无法启动。非常感谢所有帮助!
【问题讨论】:
把这个放到队列中 【参考方案1】:原来我的更新导致需要添加新的 firebase 依赖项。
在 pubspec.yaml 中,不得不添加:
firebase_core: ^0.5.2
而且主要是添加
await Firebase.initializeApp();
就在之前
runApp(MyApp());
【讨论】:
以上是关于Provider.of 总是返回 null Flutter的主要内容,如果未能解决你的问题,请参考以下文章
无法使用 Provider.of(context) 调用类方法