I'm attempting to enable auto-login by obtaining a token saved in the local mobile instance. I'm encountering this error. I'm using Provider for state management. In my main file , I want to retrieve my token to check whether user has been logged in or not. What i'm, doing wrong ?
My Error
E/flutter ( 6547): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: No ScaffoldMessenger widget found.
E/flutter ( 6547): MyApp widgets require a ScaffoldMessenger widget ancestor.
E/flutter ( 6547): The specific widget that could not find a ScaffoldMessenger ancestor was:
E/flutter ( 6547): MyApp
E/flutter ( 6547): The ancestors of this widget were:
E/flutter ( 6547): _InheritedProviderScope<UserProvider?>
E/flutter ( 6547): ChangeNotifierProvider<UserProvider>
E/flutter ( 6547): _NestedHook
E/flutter ( 6547): MultiProvider
E/flutter ( 6547): [root]
E/flutter ( 6547): Typically, the ScaffoldMessenger widget is introduced by the MaterialApp at the top of your application widget tree.
Main.dart file
void main() {
runApp(MultiProvider(
providers: [ChangeNotifierProvider(create: (context) => UserProvider())],
child: const MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}):super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final AuthService authService = AuthService();
@override
void initState() {
// TODO: implement initState
authService.getUserData(context);
super.initState();
}
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ShopOne',
theme: ThemeData(
scaffoldBackgroundColor: GlobalVariables.backgroundColor,
textTheme: Theme.of(context)
.textTheme
.apply(bodyColor: Colors.white, displayColor: Colors.white),
colorScheme:
const ColorScheme.light(primary: GlobalVariables.secondaryColor),
appBarTheme: const AppBarTheme(
elevation: 0, iconTheme: IconThemeData(color: Colors.white)),
//
primarySwatch: Colors.blue,
),
debugShowCheckedModeBanner: false,
onGenerateRoute: ((settings) => generateRoute(settings)),
home: Provider.of<UserProvider>(context).user.token.isNotEmpty
? const HomeScreen()
: const AuthScreen()
);
if (Provider.of<UserProvider>(context).user.token.isNotEmpty) {
print('true');
} else {
print('false');
;
}
}
}
get user function
void getUserData(
BuildContext context,
) async {
try {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString("auth-token");
if (token == null) {
prefs.setString('auth-token', '');
}
var tokenRes = await http.post(Uri.parse('$uri//tokenisvalid'),
headers: <String, String>{
'Content-Type': 'application/json;charset=UTF-8',
'auth-token': token!
});
print('tokenres working 1');
var response = jsonDecode(tokenRes.body);
if (response == true) {
http.Response userRes = await http.get(Uri.parse('$uri/'),
headers: <String, String>{
'Content-type': 'application/json;charset=UTF-8',
'auth-token': token
});
print('tokenres working 2');
var userProvider = Provider.of<UserProvider>(context, listen: false);
userProvider.setUser(userRes.body);
}
} catch (e) {
showSnackBar(context, e.toString());
}
}
CodePudding user response:
This happened because the context
that you used in showSnackBar
, doesn't belongs to any Scaffold
, you need to separate the MaterialApp's home
to new StatefulWidget
class like this:
class ScreenManager extends StatefulWidget {
const ScreenManager({Key? key}) : super(key: key);
@override
State<ScreenManager> createState() => _ScreenManagerState();
}
class _ScreenManagerState extends State<ScreenManager> {
@override
void initState() {
// TODO: implement initState
authService.getUserData(context);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Provider.of<UserProvider>(context).user.token.isNotEmpty
? const HomeScreen()
: const AuthScreen(),
);
}
void getUserData(BuildContext context) async {
try {
...
} catch (e) {
WidgetsBinding.instance.addPostFrameCallback((_) {
showSnackBar(context, e.toString());
});
}
}
}
then use it like this:
home: ScreenManager();
Note: don't forget to remove authService.getUserData(context)
from _MyAppState's initState
.