Flutter bloc_pattern returning NoSuchMethodError - flutter

I am building my first Flutter app, and foolishly enough, I started off with complex structures such as the MVVM, I don't know very much about it but have tried.
Here is my folder structure:
lib
---models
------videos.dart
---repos
------videos.dart
---viewmodels
------videos.dart
main.dart (I know)
In my main.dart file, I am using StreamBuilder to fetch the lisit of videos, here's the code:
class Home extends StatelessWidget {
VideosBloc videosBloc = BlocProvider.getBloc<VideosBloc>();
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
flex: 1,
child: CustomAppBar(),
),
Expanded(
flex: 9,
child: Container(
color: Theme.of(context).primaryColorDark,
child: StreamBuilder(
stream: videosBloc.videosStream,
builder: (context, snapshot) {
List<Video> videos = snapshot != null ? snapshot.data : [];
return ListView(
children: videos.map((video) {
return VideoContainer(video);
}).toList(),
);
},
),
),
)
],
);
}
}
There there is this bloc file:
import 'dart:async';
import 'package:bloc_pattern/bloc_pattern.dart';
import 'package:peeke_vines/models/videos.dart';
import 'package:peeke_vines/repositories/videos.dart';
import 'package:rxdart/rxdart.dart';
class VideosBloc extends BlocBase {
VideosBloc();
//Stream that receives a number and changes the count;
var _videosController =
BehaviorSubject<List<Video>>.seeded(VideosRepo().getVideos());
//output
Stream<List<Video>> get videosStream => _videosController.stream;
//input
Sink<List<Video>> get videosSink => _videosController.sink;
//dispose will be called automatically by closing its streams
#override
void dispose() {
_videosController.close();
super.dispose();
}
}
And this bloc gets this data from a repository
import 'package:peeke_vines/models/videos.dart';
class VideosRepo {
VideosRepo();
List<Video> videos = VideoModel().fetchVideos();
List<Video> getVideos() {
return [];
}
}
And this repository currently just gets the data from a model, but later I'll implement a web service to fetch the data from:
import 'package:meta/meta.dart';
class VideoModel {
List<Video> fetchVideos() {
return [
Video(
video: 'assets/videos/main.wmv',
title: 'Peeke Vines Video Title',
date: '2 Days ago',
thumbnail: 'assets/thumbnails/1.jpg',
duration: 13.5),
Video(
video: 'assets/videos/main.wmv',
title: 'Peeke Vines Video Title',
date: '2 Days ago',
thumbnail: 'assets/thumbnails/2.jpg',
duration: 13.5),
Video(
video: 'assets/videos/main.wmv',
title: 'Peeke Vines Video Title',
date: '2 Days ago',
thumbnail: 'assets/thumbnails/1.jpg',
duration: 13.5)
];
}
}
class Video {
String video, title, date, thumbnail;
double duration;
Video(
{#required this.video,
#required this.title,
#required this.date,
#required this.thumbnail,
#required this.duration});
}
Now, whenever I import the bloc in the main.dart file using this line:
VideosBloc videosBloc = BlocProvider.getBloc<VideosBloc>();
I get this error:
I/flutter ( 4338): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 4338): The following NoSuchMethodError was thrown building MyApp(dirty):
I/flutter ( 4338): Class 'NoSuchMethodError' has no instance getter 'message'.
I/flutter ( 4338): Receiver: Instance of 'NoSuchMethodError'
I/flutter ( 4338): Tried calling: message
I/flutter ( 4338):
I/flutter ( 4338): When the exception was thrown, this was the stack:
I/flutter ( 4338): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:50:5)
I/flutter ( 4338): #1 BlocProvider.getBloc (package:bloc_pattern/src/bloc_provider.dart:47:12)
I/flutter ( 4338): #2 new Home (package:peeke_vines/main.dart:35:40)
I/flutter ( 4338): #3 MyApp.build (package:peeke_vines/main.dart:21:20)
I/flutter ( 4338): #4 StatelessElement.build (package:flutter/src/widgets/framework.dart:3974:28)
I/flutter ( 4338): #5 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3924:15)
I/flutter ( 4338): #6 Element.rebuild (package:flutter/src/widgets/framework.dart:3721:5)
I/flutter ( 4338): #7 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3907:5)
I/flutter ( 4338): #8 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3902:5)
I/flutter ( 4338): #9 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3084:14)
I/flutter ( 4338): #10 Element.updateChild (package:flutter/src/widgets/framework.dart:2887:12)
I/flutter ( 4338): #11 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:939:16)
I/flutter ( 4338): #12 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:910:5)
I/flutter ( 4338): #13 RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:856:17)
I/flutter ( 4338): #14 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2320:19)
I/flutter ( 4338): #15 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:855:13)
Can you tell me why this error is coming?

The issue is that you are trying to get the Bloc outside of the build method.
Try to get it at the start of the build method.

Related

Running Palette Generator (by flutter team) inside an async function freezes the app for a bit

I was trying to use the palette generator plugin by flutter team. However, when I run the function, the UI freezes for two seconds or three. Here is how im trying to use it:
void _generateColorPalette(BuildContext context) async {
try {
if (this.imageData == null) {
return;
}
setState(() {
isLoading = true;
});
final PaletteGenerator _temp = await PaletteGenerator.fromImageProvider(
MemoryImage(imageData as Uint8List));
setState(() {
isLoading = false;
pallete = _temp.colors.toList();
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Pallete Generated!'),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
),
),
);
} catch (e) {
setState(() {
isLoading = false;
});
print('Error occured while generating the palette: $e');
}
}
I also tried using it in a compute function but to no avail cause i get this error:
Restarted application in 2,281ms.
I/Timeline( 4948): Timeline: Activity_launch_request time:96984061
W/Activity( 4948): Slow Operation: Activity com.example.glitter/.MainActivity onActivityResult took 187ms
I/flutter ( 4948): ══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞════════════════════════════════════════════════════
I/flutter ( 4948): The following _CastError was thrown while resolving an image:
I/flutter ( 4948): Null check operator used on a null value
I/flutter ( 4948):
I/flutter ( 4948): When the exception was thrown, this was the stack:
I/flutter ( 4948): #0 ImageProvider.resolveStreamForKey
I/flutter ( 4948): #1 ImageProvider.resolve.<anonymous closure>
I/flutter ( 4948): #2 ImageProvider._createErrorHandlerAndKey.<anonymous closure>.<anonymous closure>
I/flutter ( 4948): #3 SynchronousFuture.then
I/flutter ( 4948): #4 ImageProvider._createErrorHandlerAndKey.<anonymous closure>
I/flutter ( 4948): #8 ImageProvider._createErrorHandlerAndKey
I/flutter ( 4948): #9 ImageProvider.resolve
I/flutter ( 4948): #10 PaletteGenerator.fromImageProvider
I/flutter ( 4948): #11 _ImageScreenState.generatePallete
I/flutter ( 4948): #12 _IsolateConfiguration.apply
I/flutter ( 4948): #13 _spawn.<anonymous closure>
I/flutter ( 4948): #14 _spawn.<anonymous closure>
I/flutter ( 4948): #15 Timeline.timeSync (dart:developer/timeline.dart:163:22)
I/flutter ( 4948): #16 _spawn
I/flutter ( 4948): #17 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:286:17)
I/flutter ( 4948): (elided 4 frames from class _RawReceivePortImpl and dart:async)
I/flutter ( 4948):
I/flutter ( 4948): Image provider: MemoryImage(Uint8List#e9679, scale: 1.0)
I/flutter ( 4948): Image configuration: ImageConfiguration(devicePixelRatio: 1.0)
I/flutter ( 4948): Image key: MemoryImage(Uint8List#e9679, scale: 1.0)
I/flutter ( 4948): ════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter ( 4948): Error occured: TimeoutException: Timeout occurred trying to load from MemoryImage(Uint8List#e9679, scale: 1.0)
Reloaded 1 of 949 libraries in 1,408ms.
I/flutter ( 4948): ══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞════════════════════════════════════════════════════
I/flutter ( 4948): The following _CastError was thrown while resolving an image:
I/flutter ( 4948): Null check operator used on a null value
I/flutter ( 4948):
I/flutter ( 4948): When the exception was thrown, this was the stack:
I/flutter ( 4948): #0 ImageProvider.resolveStreamForKey
I/flutter ( 4948): #1 ImageProvider.resolve.<anonymous closure>
I/flutter ( 4948): #2 ImageProvider._createErrorHandlerAndKey.<anonymous closure>.<anonymous closure>
I/flutter ( 4948): #3 SynchronousFuture.then
I/flutter ( 4948): #4 ImageProvider._createErrorHandlerAndKey.<anonymous closure>
I/flutter ( 4948): #8 ImageProvider._createErrorHandlerAndKey
I/flutter ( 4948): #9 ImageProvider.resolve
I/flutter ( 4948): #10 PaletteGenerator.fromImageProvider
I/flutter ( 4948): #11 _ImageScreenState.generatePallete
I/flutter ( 4948): #12 _IsolateConfiguration.apply
I/flutter ( 4948): #13 _spawn.<anonymous closure>
I/flutter ( 4948): #14 _spawn.<anonymous closure>
I/flutter ( 4948): #15 Timeline.timeSync (dart:developer/timeline.dart:163:22)
I/flutter ( 4948): #16 _spawn
I/flutter ( 4948): #17 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:286:17)
I/flutter ( 4948): (elided 4 frames from class _RawReceivePortImpl and dart:async)
I/flutter ( 4948):
I/flutter ( 4948): Image provider: MemoryImage(Uint8List#53605, scale: 1.0)
I/flutter ( 4948): Image configuration: ImageConfiguration(devicePixelRatio: 1.0)
I/flutter ( 4948): Image key: MemoryImage(Uint8List#53605, scale: 1.0)
I/flutter ( 4948): ════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter ( 4948): Error occured: TimeoutException: Timeout occurred trying to load from MemoryImage(Uint8List#53605, scale: 1.0)
Reloaded 2 of 949 libraries in 1,273ms.
Heres how I was trying to use it in isolate:
void _generateColorPalette(BuildContext context) async {
try {
if (this.imageData == null) {
return;
}
setState(() {
isLoading = true;
});
// final PaletteGenerator _temp = await PaletteGenerator.fromImageProvider(
// MemoryImage(imageData as Uint8List));
final List<Color>? _temp =
await compute(generatePalette, imageData as Uint8List);
if (_temp == null) {
return;
}
setState(() {
isLoading = false;
// pallete = _temp.colors.toList();
pallete = _temp;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Pallete Generated!'),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
),
),
);
} catch (e) {
setState(() {
isLoading = false;
});
print('Error occured while generating the palette: $e');
}
}
and the isolated function:
Future<List<Color>?> generatePalette(Uint8List _image) async {
try {
final PaletteGenerator _generator =
await PaletteGenerator.fromImageProvider(MemoryImage(_image));
return _generator.colors.toList();
} catch (e) {
print('Error occured while generating palette in the isolate: $e');
}
}
Any ideas on what might be missing?

I am getting error like this Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe

What I trying to do here is getting data from the 000webhost.com and passing that to my model class. That model class is being passed to the provider. Now when I try to display the information in my screen i am getting error.
In this case i have a model class called StudentData.
class StudentData {
final String rollNumber;
final String firstName;
final String lastName;
StudentData({
this.rollNumber,
this.firstName,
this.lastName,
});
}
Here I am fetching data using http package from internet.
And passing the decoded data to the StudentData class and passing that to my data_provider
import 'package:http/http.dart' as http;
void getStudentData(String currentEmail, BuildContext context) async {
final _url = 'https://aaa.000webhostapp.com/getStudentData.php';
final response = await http.post(_url, body: {'email': currentEmail});
var data = response.body;
final decodedData = jsonDecode(data);
final myRollNumber = decodedData['roll_number'];
final myFirstName = decodedData['first_name'];
final myLastName = decodedData['last_name'];
final myStudentData = StudentData(
rollNumber: myRollNumber, firstName: myFirstName, lastName: myLastName);
Provider.of<DataProvider>(context, listen: false)
.getMyStudentData(myStudentData);
}
Here is my DataProvider
class DataProvider extends ChangeNotifier {
StudentData myStudentData;
void getMyStudentData(StudentData studentData) {
myStudentData = studentData;
notifyListeners();
}
}
After that I have tried to fetch those information in my Screen
class StudentDashboard extends StatelessWidget {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Center(
child:
Text(Provider.of<DataProvider>(context).myStudentData.rollNumber),
),
),
);
}
}
Then the error be like
======== Exception caught by widgets library =======================================================
The following NoSuchMethodError was thrown building StudentDashboard(dirty, dependencies: [_InheritedProviderScope<DataProvider>]):
The getter 'rollNumber' was called on null.
Receiver: null
Tried calling: rollNumber
The relevant error-causing widget was:
StudentDashboard file:///D:/Other/App/Flutter/my_ecampus/lib/views/screens/auth_screens/login_screen.dart:62:53
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1 StudentDashboard.build (package:my_ecampus/views/screens/main_screens/student_screens/student_dashboard.dart:38:69)
#2 StatelessElement.build (package:flutter/src/widgets/framework.dart:4701:28)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4627:15)
#4 Element.rebuild (package:flutter/src/widgets/framework.dart:4343:5)
...
====================================================================================================
E/flutter ( 7682): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
E/flutter ( 7682): At this point the state of the widget's element tree is no longer stable.
E/flutter ( 7682): 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 ( 7682): #0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure> (package:flutter/src/widgets/framework.dart:3906:9)
E/flutter ( 7682): #1 Element._debugCheckStateIsActiveForAncestorLookup (package:flutter/src/widgets/framework.dart:3920:6)
E/flutter ( 7682): #2 Element.getElementForInheritedWidgetOfExactType (package:flutter/src/widgets/framework.dart:3986:12)
E/flutter ( 7682): #3 Provider._inheritedElementOf (package:provider/src/provider.dart:324:34)
E/flutter ( 7682): #4 Provider.of (package:provider/src/provider.dart:281:30)
E/flutter ( 7682): #5 getStudentData (package:my_ecampus/business_view/services/database/getData_database.dart:19:12)
E/flutter ( 7682): <asynchronous suspension>
E/flutter ( 7682): #6 LoginScreen._login (package:my_ecampus/views/screens/auth_screens/login_screen.dart:60:9)
E/flutter ( 7682): <asynchronous suspension>
E/flutter ( 7682): #7 LoginScreen.build.<anonymous closure>.<anonymous closure> (package:my_ecampus/views/screens/auth_screens/login_screen.dart:198:31)
E/flutter ( 7682): #8 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:993:19)
E/flutter ( 7682): #9 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:1111:38)
E/flutter ( 7682): #10 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:183:24)
E/flutter ( 7682): #11 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:598:11)
E/flutter ( 7682): #12 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:287:5)
E/flutter ( 7682): #13 BaseTapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:259:7)
E/flutter ( 7682): #14 GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:157:27)
E/flutter ( 7682): #15 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:362:20)
E/flutter ( 7682): #16 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:338:22)
E/flutter ( 7682): #17 RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:267:11)
E/flutter ( 7682): #18 GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:295:7)
E/flutter ( 7682): #19 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:240:7)
E/flutter ( 7682): #20 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:213:7)
E/flutter ( 7682): #21 _rootRunUnary (dart:async/zone.dart:1206:13)
E/flutter ( 7682): #22 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter ( 7682): #23 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1005:7)
E/flutter ( 7682): #24 _invoke1 (dart:ui/hooks.dart:265:10)
E/flutter ( 7682): #25 _dispatchPointerDataPacket (dart:ui/hooks.dart:174:5)
E/flutter ( 7682):
This is my main class and i am using multiprovider here.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<WidgetProvider>(
create: (context) => WidgetProvider()),
ChangeNotifierProvider<DataProvider>(
create: (context) => DataProvider()),
],
child: MaterialApp(
home: LoginScreen(),
),
);
}
}
This is where I call getStudentData function
void _login({String email, String password, BuildContext context}) async {
final loginResponse =
await loginDatabase(email: email, password: password, context: context);
if (loginResponse.isNotEmpty) {
final isStaff = email.contains(RegExp(r'.ce#srit.org$'));
if (isStaff == true) {
getStaffData(email, context);
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => StaffDashboard()));
} else {
getStudentData(email, context);//here is the getStudentData() function
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) => StudentDashboard()));
}
} else {
print('Login Failed from loginDatabase(){}');
}
}
The HTTP request is sent to the provider listen: false because it can not listen. So that you can call the method. That's why I designed it from scratch for you. I hope you understand. It will probably work if you do it as I did.
import 'package:http/http.dart' as http;
Future<StudentData> _getStudentData(String currentEmail, BuildContext context)async {
final _url = 'https://aaa.000webhostapp.com/getStudentData.php';
final response = await http.post(_url, body: {'email': currentEmail});
var data = response.body;
if (data.isEmpty) return null;
final decodedData = jsonDecode(data);
final myRollNumber = decodedData['roll_number'];
final myFirstName = decodedData['first_name'];
final myLastName = decodedData['last_name'];
final myStudentData = StudentData(
rollNumber: myRollNumber, firstName: myFirstName, lastName: myLastName);
return MystudentData;
}
class DataProvider extends ChangeNotifier {
StudentData myStudentData;
void getMyStudentData(StudentData studentData) {
myStudentData = studentData;
notifyListeners();
}
}
Future getMyStudentDataAsync() async {
StudentData result = await _getStudentData();
getMyStudentData(result);
}
class StudentDashboard extends StatelessWidget {
#override
void initState() {
super.initState(); getRequest();
}
future getRequest()async{
Provider.of<DataProvider>(context, listen: false)
.getMyStudentDataAsync();
}
#override
Widget build(BuildContext context) {
DataProvider _dataProvider = Provider.of<DataProvider>(context);
return SafeArea(
child: Scaffold(
body: Center(
child:
Text( _dataProvider.myStudentData.rollNumber),
),
),
);
}
}

How to make a reusable PopupMenuButton in Flutter

I want to make a reusable PopupMenuButton in flutter, so i can call that widget and assign the PopupMenuItem dynamically.
Here is what i've done, but it throw a framework error. I am relatively new in flutter.
here is class that supposed to be reusable:
class PopupMenu {
PopupMenu({#required this.title, #required this.onTap});
final String title;
final VoidCallback onTap;
}
class PopupmMenuButtonBuilder {
setPopup(List<PopupMenu> popupItem) {
return PopupMenuButton<String>(
onSelected: (_) {
popupItem.forEach((item) => item.onTap);
},
itemBuilder: (BuildContext context) {
popupItem.forEach(
(item) {
return <PopupMenuItem<String>>[
PopupMenuItem<String>(
value: item.title,
child: Text(
item.title,
),
),
];
},
);
},
);
}
}
and then i call the widget like this:
child: PopupmMenuButtonBuilder().setPopup([
PopupMenu(title: 'Item 1', onTap: () => print('item 1 selected')),
PopupMenu(title: 'Item 2', onTap: () => print('item 2 selected')),
]),
It shows the 3 dot icon button, but when i tap the icon it throws this error:
I/flutter ( 8509): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
I/flutter ( 8509): The following assertion was thrown while handling a gesture:
I/flutter ( 8509): 'package:flutter/src/material/popup_menu.dart': Failed assertion: line 723 pos 10: 'items != null &&
I/flutter ( 8509): items.isNotEmpty': is not true.
I/flutter ( 8509): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter ( 8509): more information in this error message to help you determine and fix the underlying cause.
I/flutter ( 8509): In either case, please report this assertion by filing a bug on GitHub:
I/flutter ( 8509): https://github.com/flutter/flutter/issues/new?template=BUG.md
I/flutter ( 8509): When the exception was thrown, this was the stack:
I/flutter ( 8509): #2 showMenu (package:flutter/src/material/popup_menu.dart:723:10)
I/flutter ( 8509): #3 _PopupMenuButtonState.showButtonMenu (package:flutter/src/material/popup_menu.dart:898:5)
I/flutter ( 8509): #4 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:511:14)
I/flutter ( 8509): #5 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:566:30)
I/flutter ( 8509): #6 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:166:24)
I/flutter ( 8509): #7 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:240:9)
I/flutter ( 8509): #8 TapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:211:7)
I/flutter ( 8509): #9 GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:156:27)
I/flutter ( 8509): #10 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:225:20)
I/flutter ( 8509): #11 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:199:22)
I/flutter ( 8509): #12 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7)
I/flutter ( 8509): #13 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)I/flutter ( 8509): #14 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)I/flutter ( 8509): #18 _invoke1 (dart:ui/hooks.dart:233:10)
I/flutter ( 8509): #19 _dispatchPointerDataPacket (dart:ui/hooks.dart:154:5)
I/flutter ( 8509): (elided 5 frames from class _AssertionError and package dart:async)
I/flutter ( 8509): Handler: onTap
I/flutter ( 8509): Recognizer:
I/flutter ( 8509): TapGestureRecognizer#8968f(debugOwner: GestureDetector, state: ready, won arena, finalPosition:
I/flutter ( 8509): Offset(339.0, 54.0), sent tap down)
I/flutter ( 8509): ════════════════════════════════════════════════════════════════════════════════════════════════════
Your itemBuilder needs to return a List. It doesn't actually return anything - note how the return is inside the forEach so it's just returning from the lambda. In general, forEach should sometimes be avoided. Also, the PopupMenuButtonBuilder class is redundant - it could be replaced with a static or top-level function.
One other thing that's unclear is why you want to call each onTap for every select. As you currently have it it's going to call every callback!
Try this:
class PopupMenu {
PopupMenu({#required this.title, #required this.onTap});
final String title;
final VoidCallback onTap;
static PopupMenuButton<String> createPopup(List<PopupMenu> popupItems) {
return PopupMenuButton<String>(
onSelected: (value) {
popupItems.firstWhere((e) => e.title == value).onTap();
},
itemBuilder: (context) => popupItems
.map((item) => PopupMenuItem<String>(
value: item.title,
child: Text(
item.title,
),
))
.toList(),
);
}
}
You can also create a changeable list to append to the Popup menu instead of manually creating it one by one in the child
child: PopupMenu(popUpList: _popUpList).createPopup()),
then in the Popup menu class
class PopupMenu {
const PopupMenu({this.popUpList});
final List<PopUpList> popUpList;
PopupMenuButton<String> createPopup() {
return PopupMenuButton<String>(
onSelected: (value) {
popUpList.firstWhere((e) => e.title == value).onTap();
},
itemBuilder: (context) => popUpList
.map((item) => PopupMenuItem<String>(
value: item.title,
child: Text(item.title),
)).toList(),
);
}
}
model
class PopUpList{
String title;
VoidCallback onTap;
PopUpList({this.onTap, this.title});
}
cheers!

From StatefulWidget navigate to StatelessWidget runs the last builder but also the first builder

Is there a way to prevent the build() from being called multiple times?
The next code creates two pages, each with one button, the button on FirstPage navigates to SecondPage, and the one on SecondsPage goes back to FirstPage.
The problem is that if you click the button on FirstPage it runs the SecondPage build() but it also runs the FirstPage build().
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'First page',
home: FirstPage(),
);
}
}
class FirstPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _FirstPageState();
}
}
class _FirstPageState extends State<FirstPage> {
#override
Widget build(BuildContext context) {
print('---------- In FirstPage build ----------');
return Scaffold(
appBar: AppBar(
title: Text('First page'),
),
body: Column(
children: [
Text('First page body'),
FlatButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
);
},
child: Text('Go to second page')
)
]
)
);
}
}
class SecondPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
print('---------- In SecondPage build ----------');
return Scaffold(
appBar: AppBar(
title: Text('Second page'),
),
body: Column(
children: [
Text('Second page body'),
FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back')
)
]
)
);
}
}
Console output:
Performing hot restart...
D/dalvikvm(23908): threadid=12: interp stack at 0x76040000
Restarted app in 3,849ms.
I/flutter (23908): ---------- In FirstPage build ----------
I/SurfaceTextureClient(23908): [STC::queueBuffer] (this:0x76b39810) fps:0.07, dur:14731.13, max:14731.13, min:14731.13
I/SurfaceTextureClient(23908): [STC::queueBuffer] this:0x76b39810, api:1, last queue time elapsed:14731.13
After click button:
V/Provider/Settings(23908): from db cache, name = sound_effects_enabled , value = 0
I/flutter (23908): ---------- In SecondPage build ----------
I/SurfaceTextureClient(23908): [STC::queueBuffer] (this:0x76b39810) fps:0.24, dur:4140.60, max:4140.60, min:4140.60
I/flutter (23908): ---------- In FirstPage build ----------
Thanks for your help.
EDIT:
I tryed using popAndPushNamed() on FirstPage it just runs the build on the SecondPage but if I try to go back with:
Navigator.popAndPushNamed(
context,
'/'
);
I get the error:
I/flutter ( 5005): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
I/flutter ( 5005): The following assertion was thrown while handling a gesture:
I/flutter ( 5005): Cannot reuse a MaterialPageRoute<dynamic> after disposing it.
I/flutter ( 5005): 'package:flutter/src/widgets/routes.dart': Failed assertion: line 215 pos 12:
I/flutter ( 5005): '!_transitionCompleter.isCompleted'
I/flutter ( 5005): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter ( 5005): more information in this error message to help you determine and fix the underlying cause.
I/flutter ( 5005): In either case, please report this assertion by filing a bug on GitHub:
I/flutter ( 5005): https://github.com/flutter/flutter/issues/new
I/flutter ( 5005): When the exception was thrown, this was the stack:
I/flutter ( 5005): #2 TransitionRoute.didPopNext (package:flutter/src/widgets/routes.dart)
I/flutter ( 5005): #3 NavigatorState.pop (package:flutter/src/widgets/navigator.dart:1691:23)
I/flutter ( 5005): #4 NavigatorState.popAndPushNamed (package:flutter/src/widgets/navigator.dart:1399:5)
I/flutter ( 5005): #5 Navigator.popAndPushNamed (package:flutter/src/widgets/navigator.dart:731:34)
I/flutter ( 5005): #6 SecondPage.build.<anonymous closure> (file:///home/ncs/Documents/flutter/src/test1/lib/main.dart:83:25)
I/flutter ( 5005): #7 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:494:14)
I/flutter ( 5005): #8 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:549:30)
I/flutter ( 5005): #9 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
I/flutter ( 5005): #10 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:161:9)
I/flutter ( 5005): #11 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:94:7)
I/flutter ( 5005): #12 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
I/flutter ( 5005): #13 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
I/flutter ( 5005): #14 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
I/flutter ( 5005): #15 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:143:19)
I/flutter ( 5005): #16 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:121:22)
I/flutter ( 5005): #17 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:101:7)
I/flutter ( 5005): #18 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:64:7)
I/flutter ( 5005): #19 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:48:7)
I/flutter ( 5005): #20 _invoke1 (dart:ui/hooks.dart:134:13)
I/flutter ( 5005): #21 _dispatchPointerDataPacket (dart:ui/hooks.dart:91:5)
I/flutter ( 5005): (elided 2 frames from class _AssertionError)
I/flutter ( 5005): Handler: onTap
I/flutter ( 5005): Recognizer:
I/flutter ( 5005): TapGestureRecognizer#94626(debugOwner: GestureDetector, state: possible, won arena, finalPosition:
I/flutter ( 5005): Offset(65.3, 119.6), sent tap down)
I/flutter ( 5005): ════════════════════════════════════════════════════════════════════════════════════════════════════
The only way I'm able to remove the unwanted build is by having a condition like::
class _FirstPageState extends State<FirstPage> {
bool _canBuild = true;
#override
Widget build(BuildContext context) {
if (!_canBuild) {
return Container();
}
print('---------- In FirstPage build ----------');
...
onPressed: () {
_canBuild = false;
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
).then((_) {
_canBuild = true;
});
},
...
Is this a bad practice or can create any problems?
it is just because of widget is still in to the stack of routes. i think that flutter re-render widgets which are in the stack. if you pop FirstPage before routing to SecondPage the it will not display the message of first widget.
EDIT:
how you can use.
onPressed: () {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
);
},
Flutter always builds every "page" (widget) in the navigation stack after every push/pop. This is normal and intended behavior, so that every widget can update itself if needed.
Widget's build methods are supposed to be idempotent, whilst usually it only builds when you think it will, the framework might decide at any point to build a widget for any reason - you can't rely on any widget not building.
This is not actually a problem normally, Flutter compares all new widgets with all old widgets on a build, if the widgets are identical they will not be replaced or in any other way affected.
The short answer is thus "No", of course if you want to you can hack around this (e.g. by overriding the navigator), you definitely can.
You can view the code related to building the children of a widget (including navigator) here: https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/framework.dart
But ideally you just want to assume anything can build at any time -- as it can. Flutter makes no promises as to when it will (or wont) build your widgets, any code that is not written to take this into account is liable to break!
See this issue: https://github.com/flutter/flutter/issues/11655

The getter 'navigator' was called on null

Since this morning I have been getting this error, after looking at the stack trace, I have traced the error back to the runApp method, I don't understand
at all, what the problem is, any help would be appreciated :) This is the exception: The getter 'navigator' was called on null
Here is my main.dart file
import 'dart:async';
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_analytics/observer.dart';
import 'package:flutter/material.dart';
import 'package:savings/utils/analytics.dart';
import 'package:savings/utils/colors.dart';
import 'package:savings/pages/goals_page.dart';
import 'package:savings/utils/logic.dart' as AppLogic;
import 'package:savings/utils/models.dart' as models;
import 'package:savings/utils/variables.dart';
import 'package:flutter/services.dart';
void main() => runApp(new SavingsApp());
class SavingsApp extends StatefulWidget {
#override
_SavingsAppState createState() => new _SavingsAppState();
}
class _SavingsAppState extends State<SavingsApp> {
#override
void initState() {
initAppData();
super.initState();
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Savings',
color: primaryThemeColor,
home: GoalsPage(),
navigatorObservers: <NavigatorObserver>[analyticsObserver],
theme: new ThemeData(
primaryColor: primaryThemeColor,
accentColor: accentThemeColor,
fontFamily: "Proxima Nova",
),
);
}
#override
void dispose() {
//Good practice to close the DB
AppLogic.DatabaseInterface.closeDB();
//Handle orientation
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
super.dispose();
}
Future<Null> initAppData() async {
//Database
_initDBData();
//Analytics
analytics = new FirebaseAnalytics();
AnalyticsInterface.logAppOpen();
analyticsObserver = new FirebaseAnalyticsObserver(analytics: analytics);
}
Future<Null> _initDBData() async {
//Orientation
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
//Retrieve database from the DB interface
appDatabase = await AppLogic.DatabaseInterface.getDB();
//Log output
print("DatabaseInterface: DatabaseInitiated");
//Get a local version of the lists after the DB has been initiated
List<models.Goal> _goalsList =
await AppLogic.DatabaseInterface.getAllGoalsFromDB();
List<models.Transaction> _transactionsList =
await AppLogic.DatabaseInterface.getAllTransactionsFromDB();
//Call setState and update the global lists (which are used in the whole app) from the local ones
setState(() {
allGoalsList = _goalsList;
allTransactionsList = _transactionsList;
});
}
}
Logcat
The following NoSuchMethodError was thrown building
DefaultTextStyle(debugLabel: fallback style;
I/flutter ( 4211): consider putting your text in a Material, inherit: true,
color: Color(0xd0ff0000), family:
I/flutter ( 4211): monospace, size: 48.0, weight: 900, decoration: double
Color(0xffffff00) TextDecoration.underline,
I/flutter ( 4211): softWrap: wrapping at box width, overflow: clip):
I/flutter ( 4211): The getter 'navigator' was called on null.
I/flutter ( 4211): Receiver: null
I/flutter ( 4211): Tried calling: navigator
I/flutter ( 4211):
I/flutter ( 4211): When the exception was thrown, this was the stack:
I/flutter ( 4211): #0 Object.noSuchMethod
(dart:core/runtime/libobject_patch.dart:46:5)
I/flutter ( 4211): #1 NavigatorState.initState
(package:flutter/src/widgets/navigator.dart:1303:23)
I/flutter ( 4211): #2 StatefulElement._firstBuild
(package:flutter/src/widgets/framework.dart:3751:58)
I/flutter ( 4211): #3 ComponentElement.mount
(package:flutter/src/widgets/framework.dart:3617:5)
...
...
I/flutter ( 4211): #104 runApp (package:flutter/src/widgets/binding.dart:704:7)
I/flutter ( 4211): #105 main (file:///C:/Coding/savings/lib/main.dart:13:16)
I/flutter ( 4211): #106 _startIsolate.<anonymous closure (dart:isolate/runtime/libisolate_patch.dart:279:19)
I/flutter ( 4211): #107 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:165:12)
You are getting this error because, the navigatorObserver instance "analyticsObserver" you are passing in your navigationObservers array is being instantiated in an async function, means, possibly when the build function is running for the first time, that time your "analyticsObserver" is null.
Try adding the following condition while assigning your navigationObservers array
navigatorObservers: (null == analyticsObserver)? [] : <NavigatorObserver>[analyticsObserver],
Or simply return circular progress indicator while analyticsObserver is null.