When Using "BlocBuilder" in "MultiBlocProvider" I have get error - flutter

I am new in flutter .I am tried googling but I cant fix my problem. I used "MultiBlocProvider" for manage stats . I want change dark mode state like bellow.
ThemeCubit.dart
part 'theme_state.dart';
class ThemeCubit extends HydratedCubit<ThemeState> {
ThemeCubit() : super(ThemeState(AppThemes.lightTheme));
void getTheme(ThemeState state) {
emit(state);
}
#override
ThemeState? fromJson(Map<String, dynamic> json) {
return json['isDark'] as bool
? ThemeState(AppThemes.darkTheme)
: ThemeState(AppThemes.lightTheme);
}
#override
Map<String, bool>? toJson(ThemeState state) {
return {'isDark': state.themeData.brightness == Brightness.dark};
}
}
ThemeState.dart
part of 'theme_cubit.dart';
#immutable
class ThemeState extends Equatable {
final ThemeData themeData;
const ThemeState(this.themeData);
#override
List<Object?> get props => [themeData];
}
main.dart
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
lazy: true,
create: (context) => ThemeCubit(),
),
],
child:BlocBuilder<ThemeCubit, ThemeState>(
builder: (context,state) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Production Boilerplate',
theme: state.themeData, //ThemeMode.dark,
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
},
),
);
}
}
settingScreen.dart
Positioned(
top: 60 - widget.offset / 2,
left: 20,
child: Builder(builder: (context) {
return Switch(
value:newValue ,
onChanged: (value) {
BlocProvider.of<ThemeCubit>(context).getTheme(ThemeState(
newValue ? AppThemes.darkTheme : AppThemes.lightTheme));
});
})
),
This code works properly when used "BlocProvider" . But when I used "MultiBlocProvider", I get bellow error.
The following assertion was thrown attaching to the render tree:
'package:flutter/src/widgets/framework.dart': Failed assertion: line
4357 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
Either the assertion indicates an error in the framework itself, or we
should provide substantially more information in this error message to
help you determine and fix the underlying cause. In either case,
please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=2_bug.md
When the exception was thrown, this was the stack:
#2 Element.rebuild. (package:flutter/src/widgets/framework.dart:4357:14)
#3 Element.rebuild (package:flutter/src/widgets/framework.dart:4360:6)
#4 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4643:5)
#5 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4638:5)
#6 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3673:14)
#7 Element.updateChild (package:flutter/src/widgets/framework.dart:3425:18)
#8 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1198:16)
#9 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1167:5)
#10 RenderObjectToWidgetAdapter.attachToRenderTree. (package:flutter/src/widgets/binding.dart:1112:18)
#11 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2573:19)
#12 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1111:13)
#13 WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:944:7)
#14 WidgetsBinding.scheduleAttachRootWidget. (package:flutter/src/widgets/binding.dart:924:7) (elided 13 frames
from class _AssertionError, class _RawReceivePortImpl, class _Timer,
dart:async, and dart:async-patch)
How can I fix it?

I added bellow code to ThemeCubit.dart :
bool isDarkMode = false;
ThemeMode currentTheme(){
isDarkMode?_setTheme(ThemeMode.dark) : _setTheme(ThemeMode.light);
return isDarkMode?ThemeMode.dark : ThemeMode.light;
}
void updateTheme(bool isDarkMode) {
this.isDarkMode = isDarkMode;
}
and change main.dart :
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => ThemeCubit(),
),
],
child:ElderlyApp(),
);
}
class ElderlyApp extends StatefulWidget {
const ElderlyApp({Key? key,}) : super(key: key);
#override
_ElderlyAppState createState() => _ElderlyAppState();
}
class _ElderlyAppState extends State<ElderlyApp> with WidgetsBindingObserver {
#override
void initState() {
WidgetsBinding.instance!.addObserver(this);
super.initState();
}
#override
void didChangePlatformBrightness() {
context.read<ThemeCubit>().currentTheme();
super.didChangePlatformBrightness();
}
#override
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Production Boilerplate',
theme: AppThemes.lightTheme,
darkTheme: AppThemes.darkTheme,
themeMode: context.select(
(ThemeCubit cubit) => cubit.currentTheme()), //ThemeMode.dark,
debugShowCheckedModeBanner: false,
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
and change code in seetingScreen.dart
Positioned(
top: 60 - widget.offset / 2,
left: 20,
child: Builder(builder: (context) {
bool isDark = context.select((ThemeCubit themeCubit) =>
themeCubit.state.themeMode) ==ThemeMode.dark ? true: false;
return Switch(
value: context.read<ThemeCubit>().isDarkMode,
onChanged: (value) {
context.read<ThemeCubit>().updateTheme(value);
});
})),

Related

Flutter: Geolocator gives wrong location

When I execute, (click on the "show Longitude and Latitude" button) I have two problems, a wrong position and an error:
**W/GooglePlayServicesUtil( 5181): com.example.geolocalisation_youtube requires the Google Play Store, but it is missing.
I/flutter ( 5181): 10681894.898369517
I/flutter ( 5181): long c.longitude
I/flutter ( 5181): 37.421998333333335
E/flutter ( 5181): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(IO_ERROR, A network error occurred trying to lookup the supplied coordinates (latitude: 37.421998, longitude: -122.084000)., null, null)
E/flutter ( 5181): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:653:7)
E/flutter ( 5181): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:296:18)
E/flutter ( 5181): <asynchronous suspension>
E/flutter ( 5181): #2 MethodChannelGeocoding.placemarkFromCoordinates (package:geocoding_platform_interface/src/implementations/method_channel_geocoding.dart:56:24)
E/flutter ( 5181): <asynchronous suspension>
E/flutter ( 5181): #3 _MyHomePageState.build.<anonymous closure> (package:geolocalisation_youtube/main.dart:84:47)
E/flutter ( 5181): <asynchronous suspension>
**
Here’s the code:
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:awesome_dialog/awesome_dialog.dart';
import 'package:geocoding/geocoding.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future getPosition() async{
bool service= await Geolocator.isLocationServiceEnabled();
LocationPermission per= await Geolocator.checkPermission();
if (per==LocationPermission.denied){
per= await Geolocator.requestPermission();
if(per!=LocationPermission.denied){
}
}
print(service);
print("---------------");
print(per);
print("---------------");
if(!service ){
AwesomeDialog(
context: context,
title: "services",
body:
Text("service is enabled")
)..show();
}
}
Future <Position> getLatandLong() async{
return await Geolocator.getCurrentPosition().then((value) => value);
}
#override
void initState(){
getPosition();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: [
Container(
height: 500,
width:400 ,
),
ElevatedButton(
onPressed: () async{
var c = await getLatandLong();
var distance= await Geolocator.distanceBetween(c.latitude, c.longitude, 28.033886, 1.659626);
print(distance);
print("long c.longitude ");
print(c.latitude);
List<Placemark> placemarks = await placemarkFromCoordinates(c.latitude, c.longitude);
print(placemarks[0].administrativeArea);
},
child: Text(" show Longitude and Latitude"))
],
),
);
}
}
I got this error on the latest version of Android Studio.

Unhandled Exception: No ScaffoldMessenger widget found

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

type 'String' is not a subtype of type 'Map<String, String>' in type cast

when I click on a button in my Flutter App I got an error
anyone here has a solution?!
The routes
routes:{
'/':(context) => CategoriesScreen(), // the HomePage
CategoryMealsScreen.routeName: (context) => CategoryMealsScreen(),}
The arguments
void selectCategory(BuildContext ctx) {
Navigator.of(ctx).pushNamed(CategoryMealsScreen.routeName,
arguments: {
'id': id,
'title': title,
});
and the map
Widget build(BuildContext context) {
final routeArg = ModalRoute.of(context)?.settings.arguments as Map<String, String>; // the question mark is needed but I don't know why..!
final categoryId = routeArg["id"];
final categoryTitle = routeArg["title"];
final categoryMeals = DUMMY_MEALS.where((meal){
return meal.categories.contains(categoryId);
}).toList();
The full error
The following _CastError was thrown building CategoryMealsScreen(dirty, dependencies: [_ModalScopeStatus], state: _CategoryMealsScreenState#b3c64):
type 'String' is not a subtype of type 'Map<String, String>' in type cast
The relevant error-causing widget was:
CategoryMealsScreen file:///C:/Users/DELL/AndroidStudioProjects/meal_app/lib/main.dart:37:50
When the exception was thrown, this was the stack:
#0 _CategoryMealsScreenState.build (package:meal_app/screens/category_meals_screen.dart:16:65)
#1 StatefulElement.build (package:flutter/src/widgets/framework.dart:4691:27)
#2 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4574:15)
#3 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4746:11)
#4 Element.rebuild (package:flutter/src/widgets/framework.dart:4267:5)
Demo
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(debugShowCheckedModeBanner: false, routes: {
'/': (context) => CategoriesScreen(), // the HomePage
CategoryMealsScreen.routeName: (context) => CategoryMealsScreen(),
});
}
}
class CategoriesScreen extends StatefulWidget {
CategoriesScreen({Key? key}) : super(key: key);
#override
_MyWidgetXState createState() => _MyWidgetXState();
}
class _MyWidgetXState extends State<CategoriesScreen> {
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Navigator.of(context)
.pushNamed(CategoryMealsScreen.routeName, arguments: {
'id': "id 1",
'title': "title",
});
},
child: Text("pop"),
),
],
),
);
}
}
class CategoryMealsScreen extends StatefulWidget {
static final String routeName = "/asdasd";
CategoryMealsScreen({Key? key}) : super(key: key);
#override
_MyW2State createState() => _MyW2State();
}
class _MyW2State extends State<CategoryMealsScreen> {
#override
Widget build(BuildContext context) {
final routeArg = ModalRoute.of(context)?.settings.arguments as Map<String,
String>; // the question mark is needed but I don't know why..!
final categoryId = routeArg["id"];
final categoryTitle = routeArg["title"];
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("pop, $categoryTitle $categoryId"),
),
),
);
}
}

Exception caught by gesture : The following NoSuchMethodError was thrown while handling a gesture:

I'm a newbie to programming and Flutter.
On my app, I've built a page navigator with a int variable. Upon change in the integer value, I would like the app to route the user to the specific designated page. However, I'm getting an 'anonymous closure' error onPressed.
Would appreciate if someone could explain why I'm getting this error and post a rectified version of this code?
Below is the full error snippet in the debugger.
Reloaded 1 of 529 libraries in 885ms.
flutter: Page #1 Clicked
════════ Exception caught by gesture ═══════════════════════════════════════════
The following NoSuchMethodError was thrown while handling a gesture:
The method 'call' was called on null.
Receiver: null
Tried calling: call()
When the exception was thrown, this was the stack
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1 _MyHomePageState.build.<anonymous closure>
package:navigator_test/main.dart:45
#2 _InkResponseState._handleTap
package:flutter/…/material/ink_well.dart:993
#3 _InkResponseState.build.<anonymous closure>
package:flutter/…/material/ink_well.dart:1111
#4 GestureRecognizer.invokeCallback
package:flutter/…/gestures/recognizer.dart:183
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#5df0c
debugOwner: GestureDetector
state: possible
won arena
finalPosition: Offset(208.7, 509.7)
finalLocalPosition: Offset(76.7, 19.7)
button: 1
sent tap down
════════════════════════════════════════════════════════════════════════════════
Below is the depiction of the Navigator
import 'package:flutter/material.dart';
import 'package:navigator_test/main.dart';
import 'package:navigator_test/page1.dart';
class Navigator extends StatefulWidget {
#override
_NavigatorState createState() => _NavigatorState();
}
class _NavigatorState extends State<Navigator> {
int nav = 0;
void page1() {
setState(() {
nav = 1;
});
}
#override
Widget build(BuildContext context) {
if (nav < 1) {
return MyHomePage(page1: page1);
} else if (nav < 2) {
return Page1();
} else {
return null;
}
}
}
I'm importing the Function on the Main page.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
final Function page1;
MyHomePage({this.page1});
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Navigation Test'),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: 20),
FlatButton.icon(
onPressed: () {
print('Page #1 Clicked');
widget.page1();
},
icon: Icon(Icons.add_shopping_cart),
label: Text('Goto Page #1'),
)
],
),
),
// This trailing comma makes auto-formatting nicer for build methods.
);
}
}
You're getting this error because you're calling MyHomePage directly in MyApp, without passing the argument page1, so when you press 'Goto Page #1' a null function is called. To solve the problem you can instead just call Navigator in MyApp:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Navigator(),
);
}
}
But the main way to navigate to a new page without needing to call setState is to use the Navigator class of Flutter, like this (Just remember to remove your Navigator class first, so the IDE will know that you're calling flutter's Navigator class):
onPressed: () {
print('Page #1 Clicked');
//push the new route, but allowing you to go back to the previous one
Navigator.of(context).push(
//Default page transition of android
MaterialPageRoute(
builder: (context) => Page1(),
),
);
},
Or:
Navigator.of(context).push(
//Default page transition of IOS
CupertinoPageRoute(
builder: (context) => Page1(),
),
);
For more info see the docs.

Show snackbar message after widget rebuild

I try to do login page (do the transaction in some Future function) and show the error message by Snackbar.
Click login
Show loading
Future transaction done (back to original page), and then show the error message
Here is the flow I want to achieve (the last part failed):
I don't know how to show the snackBar correctly using the message from future.
showSnackBar need BuildContext but the context inside the signIn page seems no longer valid anymore after the message come back from Future.
I am now using package flutter_hooks and hooks_riverpod for the state management.
My State
class MyState{
MyState({this.data,this.isLoading});
final bool isLoading;
final String data;
MyState copyWith({data, isLoading}) => MyState(data: data, isLoading: isLoading);
}
State control and provider
Future<String> getData() fetch data and return error message
class MyStateNotifier extends StateNotifier<MyState> {
MyStateNotifier(MyState state) : super(state);
Future<String> getData() async {
state = state.copyWith(isLoading: true);
await Future.delayed(Duration(seconds: 3)); // simulate getting data
state = state.copyWith(isLoading: false, data: 'some data');
return 'error message';
}
}
final myStateProvider = StateNotifierProvider<MyStateNotifier>((ref) {
return MyStateNotifier(MyState(data: null, isLoading: false));
});
My widget
myState.isLoading: show loading page or sign in page
class WidgetA extends HookWidget {
const WidgetA({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
final myState = useProvider(myStateProvider.state);
return Center(
child: myState.isLoading ? CircularProgressIndicator() : SignInPage(),
);
}
}
class SignInPage extends HookWidget {
const SignInPage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () async {
context.read(myStateProvider).getData().then(
(message) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message)));
},
);
},
child: Text('login'),
);
}
}
I use showSnackBar inside then after getData(), but it show the error message:
E/flutter ( 6869): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: Looking up a
deactivated widget's ancestor is unsafe.
E/flutter ( 6869): At this point the state of the widget's element tree is no longer stable.
E/flutter ( 6869): To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
E/flutter ( 6869): #0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> (package:flutter/src/widgets/framework.dart:3938:9)
E/flutter ( 6869): #1 Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:3952:6)
E/flutter ( 6869): #2 Element.findAncestorWidgetOfExactType (package:flutter/src/widgets/framework.dart:4044:12)
E/flutter ( 6869): #3 debugCheckHasScaffoldMessenger.<anonymous closure> (package:flutter/src/material/debug.dart:142:17)
E/flutter ( 6869): #4 debugCheckHasScaffoldMessenger (package:flutter/src/material/debug.dart:154:4)
E/flutter ( 6869): #5 ScaffoldMessenger.of (package:flutter/src/material/scaffold.dart:218:12)
E/flutter ( 6869): #6 SignInPage.build.<anonymous closure>.<anonymous closure> (package:flutter_app_test2/main.dart:171:35)
E/flutter ( 6869): #7 _rootRunUnary (dart:async/zone.dart:1198:47)
E/flutter ( 6869): #8 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter ( 6869): #9 _FutureListener.handleValue (dart:async/future_impl.dart:143:18)
E/flutter ( 6869): #10 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:696:45)
E/flutter ( 6869): #11 Future._propagateToListeners (dart:async/future_impl.dart:725:32)
E/flutter ( 6869): #12 Future._completeWithValue (dart:async/future_impl.dart:529:5)
E/flutter ( 6869): #13 _completeOnAsyncReturn (dart:async-patch/async_patch.dart:254:13)
E/flutter ( 6869): #14 MyStateNotifier.getData (package:flutter_app_test2/main.dart)
E/flutter ( 6869): <asynchronous suspension>
You can copy paste run full code below
Reason : Because SignInPage disappear after click login button
Quick fix is use ScaffoldMessenger and provide scaffoldMessengerKey then call scaffoldMessengerKey.currentState.showSnackBar(SnackBar(content: Text(message)));
code snippet
final GlobalKey<ScaffoldMessengerState> scaffoldMessengerKey =
GlobalKey<ScaffoldMessengerState>();
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ScaffoldMessenger(
key: scaffoldMessengerKey,
child: Scaffold(
...
context.read(myStateProvider).getData().then(
(message) {
scaffoldMessengerKey.currentState
.showSnackBar(SnackBar(content: Text(message)));
},
);
working demo
full code
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hooks_riverpod/all.dart';
class MyState {
MyState({this.data, this.isLoading});
final bool isLoading;
final String data;
MyState copyWith({data, isLoading}) =>
MyState(data: data, isLoading: isLoading);
}
class MyStateNotifier extends StateNotifier<MyState> {
MyStateNotifier(MyState state) : super(state);
Future<String> getData() async {
state = state.copyWith(isLoading: true);
await Future.delayed(Duration(seconds: 3)); // simulate getting data
state = state.copyWith(isLoading: false, data: 'some data');
return 'error message';
}
}
final myStateProvider = StateNotifierProvider<MyStateNotifier>((ref) {
return MyStateNotifier(MyState(data: null, isLoading: false));
});
void main() {
runApp(
const ProviderScope(child: MyApp()),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(home: Home());
}
}
final GlobalKey<ScaffoldMessengerState> scaffoldMessengerKey =
GlobalKey<ScaffoldMessengerState>();
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ScaffoldMessenger(
key: scaffoldMessengerKey,
child: Scaffold(
appBar: AppBar(title: const Text('example')),
body: WidgetA(),
),
);
}
}
class WidgetA extends HookWidget {
const WidgetA({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
final myState = useProvider(myStateProvider.state);
return Center(
child: myState.isLoading ? CircularProgressIndicator() : SignInPage(),
);
}
}
class SignInPage extends HookWidget {
const SignInPage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () async {
context.read(myStateProvider).getData().then(
(message) {
scaffoldMessengerKey.currentState
.showSnackBar(SnackBar(content: Text(message)));
},
);
},
child: Text('login'),
);
}
}
You'll have to await you getData() request and return the message in a variable, then call the snackbar. You're trying to call the snackbar inside the future call. This can't be done on the UI.
final message = await context.read(myStateProvider).getData();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message)));