How to make a reusable PopupMenuButton in Flutter - 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!

Related

'package:flutter/src/rendering/sliver_multi_box_adaptor.dart': Failed assertion:

I try to generate a list of items out of a database (sqflite). Everything seems to work fine until my database has 3 items.
When I go to the AddBodyStatsScreen and back to the BodyStatsListScreen the program crashes. When I start debugging on AVD and I have already 3 items in the database I get the following errors:
════════ Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown building MediaQuery(MediaQueryData(size: Size(480.0, 1042.7), devicePixelRatio: 3.0, textScaleFactor: 1.0, platformBrightness: Brightness.light, padding: EdgeInsets.zero, viewPadding: EdgeInsets.zero, viewInsets: EdgeInsets.zero, alwaysUse24HourFormat: false, accessibleNavigation: false, highContrast: false, disableAnimations: false, invertColors: false, boldText: false, navigationMode: traditional, gestureSettings: DeviceGestureSettings(touchSlop: 8.0), displayFeatures: [])):
'package:flutter/src/rendering/sliver_multi_box_adaptor.dart': Failed assertion: line 261 pos 16: 'child == null || indexOf(child) > index': 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
The relevant error-causing widget was
ListView
When the exception was thrown, this was the stack
#2 RenderSliverMultiBoxAdaptor._debugVerifyChildOrder
#3 RenderSliverMultiBoxAdaptor.debugChildIntegrityEnabled=.<anonymous closure>
#4 RenderSliverMultiBoxAdaptor.debugChildIntegrityEnabled=
#5 SliverMultiBoxAdaptorElement.performRebuild
#6 SliverMultiBoxAdaptorElement.update
#7 Element.updateChild
#8 ComponentElement.performRebuild
#9 Element.rebuild
#10 ProxyElement.update
#11 Element.updateChild
#12 SingleChildRenderObjectElement.update
#13 Element.updateChild
#14 RenderObjectElement.updateChildren
#15 MultiChildRenderObjectElement.update
#16 Element.updateChild
#17 SingleChildRenderObjectElement.update
#18 Element.updateChild
#19 SingleChildRenderObjectElement.update
#20 Element.updateChild
#21 SingleChildRenderObjectElement.update
#22 Element.updateChild
#23 SingleChildRenderObjectElement.update
#24 Element.updateChild
#25 ComponentElement.performRebuild
#26 StatefulElement.performRebuild
#27 Element.rebuild
#28 StatefulElement.update
#29 Element.updateChild
#30 SingleChildRenderObjectElement.update
#31 Element.updateChild
#32 ComponentElement.performRebuild
#33 Element.rebuild
#34 ProxyElement.update
#35 Element.updateChild
#36 SingleChildRenderObjectElement.update
#37 Element.updateChild
#38 ComponentElement.performRebuild
#39 Element.rebuild
#40 ProxyElement.update
#41 Element.updateChild
#42 SingleChildRenderObjectElement.update
#43 Element.updateChild
#44 SingleChildRenderObjectElement.update
#45 Element.updateChild
#46 SingleChildRenderObjectElement.update
#47 Element.updateChild
#48 ComponentElement.performRebuild
#49 Element.rebuild
#50 ProxyElement.update
#51 Element.updateChild
#52 ComponentElement.performRebuild
#53 StatefulElement.performRebuild
#54 Element.rebuild
#55 StatefulElement.update
#56 Element.updateChild
#57 ComponentElement.performRebuild
#58 StatefulElement.performRebuild
#59 Element.rebuild
#60 StatefulElement.update
#61 Element.updateChild
#62 ComponentElement.performRebuild
#63 Element.rebuild
#64 ProxyElement.update
#65 Element.updateChild
#66 ComponentElement.performRebuild
#67 Element.rebuild
#68 StatelessElement.update
#69 Element.updateChild
#70 ComponentElement.performRebuild
#71 StatefulElement.performRebuild
#72 Element.rebuild
#73 BuildOwner.buildScope
#74 WidgetsBinding.drawFrame
#75 RendererBinding._handlePersistentFrameCallback
#76 SchedulerBinding._invokeFrameCallback
#77 SchedulerBinding.handleDrawFrame
#78 SchedulerBinding._handleDrawFrame
#79 _invoke (dart:ui/hooks.dart:145:13)
#80 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:338:5)
#81 _drawFrame (dart:ui/hooks.dart:112:31)
(elided 2 frames from class _AssertionError)
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by widgets library ═══════════════════════════════════
A RenderSliverPadding expected a child of type RenderSliver but received a child of type RenderErrorBox.
The relevant error-causing widget was
ListView
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by widgets library ═══════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 4692 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
The relevant error-causing widget was
ListView
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by widgets library ═══════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 4692 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
The relevant error-causing widget was
ListView
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by widgets library ═══════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 4692 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
The relevant error-causing widget was
ListView
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by widgets library ═══════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 4692 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
The relevant error-causing widget was
ListView
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by widgets library ═══════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 4692 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
The relevant error-causing widget was
ListView
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by widgets library ═══════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 4692 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
The relevant error-causing widget was
ListView
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by widgets library ═══════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 4692 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
The relevant error-causing widget was
ListView
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by widgets library ═══════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 4692 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
The relevant error-causing widget was
FutureBuilder<List<BodyStats>>
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by widgets library ═══════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 4692 pos 14: 'owner!._debugCurrentBuildTarget == this': is not true.
The relevant error-causing widget was
FutureBuilder<List<BodyStats>>
════════════════════════════════════════════════════════════════════════════════
Restarted application in 2.102ms.
════════ Exception caught by rendering library ═════════════════════════════════
'package:flutter/src/material/material.dart': Failed assertion: line 735 pos 12: 'referenceBox.attached': is not true.
The relevant error-causing widget was
Scaffold
════════════════════════════════════════════════════════════════════════════════
Here is the code:
import 'package:gym_app/database_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:gym_app/models/body_stats.dart';
class BodyStatsListScreen extends StatefulWidget {
const BodyStatsListScreen({super.key});
#override
_BodyStatsListScreenState createState() => _BodyStatsListScreenState();
}
class _BodyStatsListScreenState extends State<BodyStatsListScreen> {
// void _showSnackBar(BuildContext context, String text) {
// ScaffoldMessenger.of(context)
// ..hideCurrentSnackBar()
// ..showSnackBar(SnackBar(content: Text(text)));
// }
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Meine Body Stats'),
),
body: Center(
child: FutureBuilder<List<BodyStats>>(
future: DatabaseHelper.instance.getBodyStats('bodyStats'),
builder: (BuildContext context, AsyncSnapshot<List<BodyStats>> snapshot) {
if (!snapshot.hasData) {
return const Center(child: Text('Lade Daten...'));
}
return snapshot.data!.isEmpty
? const Center(
child: Text('Keine Daten vorhanden.'),
)
: ListView(
children: snapshot.data!.map((item) {
return Slidable(
// Specify a key if the Slidable is dismissible.
key: const ValueKey(0),
// The end action pane is the one at the right or the bottom side.
endActionPane: ActionPane(
motion: const ScrollMotion(),
children: [
SlidableAction(
onPressed: (context) {
Future.delayed(Duration.zero, () {
Navigator.pushNamed(context, '/addBodyStats', arguments: item).then((value) => setState(() {}));
});
},
backgroundColor: const Color.fromARGB(255, 112, 112, 112),
foregroundColor: Colors.white,
icon: Icons.edit,
label: 'editieren',
),
SlidableAction(
onPressed: (context) {
setState(() {
DatabaseHelper.instance.remove('bodyStats', item.datum!);
});
// _showSnackBar(context, '${item.datum} gelöscht');
},
backgroundColor: const Color(0xFFFE4A49),
foregroundColor: Colors.white,
icon: Icons.delete,
label: 'löschen',
),
],
),
// The child of the Slidable is what the user sees when the
// component is not dragged.
child: ListTile(title: Text(item.datum.toString())),
);
}).toList(),
);
}),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Future.delayed(Duration.zero, () {
Navigator.pushNamed(context, '/addBodyStats', arguments: BodyStats(datum: '')).then((value) => setState(() {}));
});
},
child: const Icon(Icons.add),
),
);
}
}
And the related widget to create an item:
import 'package:flutter/material.dart';
import 'package:gym_app/models/body_stats.dart';
import 'package:intl/intl.dart';
import 'package:gym_app/database_helper.dart';
class AddBodyStatsScreen extends StatefulWidget {
const AddBodyStatsScreen({super.key});
#override
State<AddBodyStatsScreen> createState() => _AddBodyStatsScreenState();
}
class _AddBodyStatsScreenState extends State<AddBodyStatsScreen> {
bool taped = false;
DateTime selectedDate = DateTime.now();
Future<void> _selectDate(BuildContext context) async {
final DateTime? picked = await showDatePicker(context: context, initialDate: selectedDate, firstDate: DateTime(2015, 8), lastDate: DateTime.now());
if (picked != null && picked != selectedDate) {
setState(() {
selectedDate = picked;
});
}
}
// void _showSnackBar(BuildContext context, String text) {
// ScaffoldMessenger.of(context)
// ..hideCurrentSnackBar()
// ..showSnackBar(SnackBar(content: Text(text)));
// }
#override
Widget build(BuildContext context) {
final editedBodyStats = ModalRoute.of(context)!.settings.arguments as BodyStats;
bool inEditMode = editedBodyStats.datum != '';
if (inEditMode && taped == false) {
selectedDate = DateFormat('dd.MM.yyyy').parse(editedBodyStats.datum!);
} else {}
return Scaffold(
appBar: AppBar(
title: Text(inEditMode ? 'Body Stats editieren' : 'Body Stats hinzufügen'),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
InkWell(
child: Text(DateFormat('dd.MM.yyyy').format(selectedDate)),
onTap: () {
taped = true;
_selectDate(context);
},
)
],
),
),
ElevatedButton(
onPressed: () async {
if (inEditMode) {
await DatabaseHelper.instance.update('bodyStats', BodyStats(datum: DateFormat('dd.MM.yyyy').format(selectedDate)));
// _showSnackBar(context, '${DateFormat('dd.MM.yyyy').format(selectedDate)} wurde editiert');
} else {
if (await DatabaseHelper.instance.uidExists('bodyStats', DateFormat('dd.MM.yyyy').format(selectedDate))) {
await DatabaseHelper.instance.update('bodyStats', BodyStats(datum: DateFormat('dd.MM.yyyy').format(selectedDate)));
// _showSnackBar(context, '${DateFormat('dd.MM.yyyy').format(selectedDate)} wurde editiert');
} else {
await DatabaseHelper.instance.add('bodyStats', BodyStats(datum: DateFormat('dd.MM.yyyy').format(selectedDate)));
}
}
Future.delayed(Duration.zero, () {
Navigator.pop(context);
});
},
child: Text(inEditMode ? 'editieren' : 'hinzufügen'),
)
],
),
);
}
}
import 'dart:io';
import 'package:gym_app/models/body_stats.dart';
// ignore: depend_on_referenced_packages
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
class DatabaseHelper {
//SingeltonPattern
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
static Database? _database;
Future<Database> get database async => _database ??= await _initDatabase();
Future<Database> _initDatabase() async {
Directory documentsDirecory = await getApplicationDocumentsDirectory();
String path = join(documentsDirecory.path, 'gym_app.db');
return await openDatabase(
path,
version: 1,
onCreate: _onCreate,
);
}
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE bodyStats(
datum TEXT PRIMARY KEY,
gewicht TEXT,
koerperfett TEXT,
muskelanteil TEXT,
halsumfang TEXT,
schulterumfang TEXT,
brustumfang TEXT,
armumfangRe TEXT,
armumfangLi TEXT,
oberschenkelumfangRe TEXT,
oberschenkelumfangLi TEXT,
bauchumfang TEXT,
hueftumfang TEXT,
wadenumfangRe TEXT,
wadenumfangLi TEXT
)
''');
}
Future<List<BodyStats>> getBodyStats(String dbTable) async {
Database db = await instance.database;
var bodyStats = await db.query(dbTable, orderBy: 'datum');
List<BodyStats> bodyStatsList = bodyStats.isNotEmpty ? bodyStats.map((e) => BodyStats.fromMap(e)).toList() : [];
return bodyStatsList;
}
Future<int> add(String dbTable, BodyStats item) async {
Database db = await instance.database;
return await db.insert(dbTable, item.toMap());
}
Future<int> remove(String dbTable, String datum) async {
Database db = await instance.database;
return await db.delete(dbTable, where: 'datum = ?', whereArgs: [datum]);
}
Future<int> update(String dbTable, BodyStats item) async {
Database db = await instance.database;
return await db.update(dbTable, item.toMap(), where: 'datum = ?', whereArgs: [item.datum]);
}
Future<bool> uidExists(String dbTable, String datum) async {
var result = await _database!.rawQuery(
'SELECT EXISTS(SELECT 1 FROM $dbTable WHERE datum= "$datum")',
);
int exists = Sqflite.firstIntValue(result)!;
return exists == 1;
}
}
import 'dart:convert';
class BodyStats {
final String? datum;
final String? gewicht;
final String? koerperfett;
final String? muskelanteil;
final String? halsumfang;
final String? schulterumfang;
final String? brustumfang;
final String? armumfangRe;
final String? armumfangLi;
final String? oberschenkelumfangRe;
final String? oberschenkelumfangLi;
final String? bauchumfang;
final String? hueftumfang;
final String? wadenumfangRe;
final String? wadenumfangLi;
BodyStats(
{this.datum,
this.gewicht,
this.koerperfett,
this.muskelanteil,
this.halsumfang,
this.schulterumfang,
this.brustumfang,
this.armumfangRe,
this.armumfangLi,
this.oberschenkelumfangRe,
this.oberschenkelumfangLi,
this.bauchumfang,
this.hueftumfang,
this.wadenumfangRe,
this.wadenumfangLi});
BodyStats copyWith(
{String? datum,
String? gewicht,
String? koerperfett,
String? muskelanteil,
String? halsumfang,
String? schulterumfang,
String? brustumfang,
String? armumfangRe,
String? armumfangLi,
String? oberschenkelumfangRe,
String? oberschenkelumfangLi,
String? bauchumfang,
String? hueftumfang,
String? wadenumfangRe,
String? wadenumfangLi}) {
return BodyStats(
datum: datum ?? this.datum,
gewicht: gewicht ?? this.gewicht,
koerperfett: koerperfett ?? this.koerperfett,
muskelanteil: muskelanteil ?? this.muskelanteil,
halsumfang: halsumfang ?? this.halsumfang,
schulterumfang: schulterumfang ?? this.schulterumfang,
brustumfang: brustumfang ?? this.brustumfang,
armumfangRe: armumfangRe ?? this.armumfangRe,
armumfangLi: armumfangLi ?? this.armumfangLi,
oberschenkelumfangRe: oberschenkelumfangRe ?? this.oberschenkelumfangRe,
oberschenkelumfangLi: oberschenkelumfangLi ?? this.oberschenkelumfangLi,
bauchumfang: bauchumfang ?? this.bauchumfang,
hueftumfang: hueftumfang ?? this.hueftumfang,
wadenumfangRe: wadenumfangRe ?? this.wadenumfangRe,
wadenumfangLi: wadenumfangLi ?? this.wadenumfangLi);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'datum': datum,
'gewicht': gewicht,
'koerperfett': koerperfett,
'muskelanteil': muskelanteil,
'halsumfang': halsumfang,
'schulterumfang': schulterumfang,
'brustumfang': brustumfang,
'armumfangRe': armumfangRe,
'armumfangLi': armumfangLi,
'oberschenkelumfangRe': oberschenkelumfangRe,
'oberschenkelumfangLi': oberschenkelumfangLi,
'bauchumfang': bauchumfang,
'hueftumfang': hueftumfang,
'wadenumfangRe': wadenumfangRe,
'wadenumfangLi': wadenumfangLi
};
}
factory BodyStats.fromMap(Map<String, dynamic> map) {
return BodyStats(
datum: map['datum'] != null ? map['datum'] as String : null,
gewicht: map['gewicht'] != null ? map['gewicht'] as String : null,
koerperfett: map['koerperfett'] != null ? map['koerperfett'] as String : null,
muskelanteil: map['muskelanteil'] != null ? map['muskelanteil'] as String : null,
halsumfang: map['halsumfang'] != null ? map['halsumfang'] as String : null,
schulterumfang: map['schulterumfang'] != null ? map['schulterumfang'] as String : null,
brustumfang: map['brustumfang'] != null ? map['brustumfang'] as String : null,
armumfangRe: map['armumfangRe'] != null ? map['armumfangRe'] as String : null,
armumfangLi: map['armumfangLi'] != null ? map['armumfangLi'] as String : null,
oberschenkelumfangRe: map['oberschenkelumfangRe'] != null ? map['oberschenkelumfangRe'] as String : null,
oberschenkelumfangLi: map['OberschenkelumfangLi'] != null ? map['oberschenkelumfangLi'] as String : null,
bauchumfang: map['bauchumfang'] != null ? map['bauchumfang'] as String : null,
hueftumfang: map['hueftumfang'] != null ? map['hueftumfang'] as String : null,
wadenumfangRe: map['wadenumfangRe'] != null ? map['wadenumfangRe'] as String : null,
wadenumfangLi: map['wadenumfangLi'] != null ? map['wadenumfangLi'] as String : null,
);
}
String toJson() => json.encode(toMap());
factory BodyStats.fromJson(String source) => BodyStats.fromMap(json.decode(source) as Map<String, dynamic>);
#override
String toString() =>
'BodyStats(datum: $datum, gewicht: $gewicht, koerperfett: $koerperfett, muskelanteil: $muskelanteil, halsumfang: $halsumfang, schulterumfang: $schulterumfang, brustumfang: $brustumfang, armumfangRe: $armumfangRe, armumfangLi: $armumfangLi, oberschenkelumfangRe: $oberschenkelumfangRe, oberschenkelumfangLi: $oberschenkelumfangLi, bauchumfang: $bauchumfang, hueftumfang: $hueftumfang, wadenumfangRe: $wadenumfangRe, wadenumfangLi: $wadenumfangLi)';
#override
bool operator ==(covariant BodyStats other) {
if (identical(this, other)) return true;
return other.datum == datum &&
other.gewicht == gewicht &&
other.koerperfett == koerperfett &&
other.muskelanteil == muskelanteil &&
other.halsumfang == halsumfang &&
other.schulterumfang == schulterumfang &&
other.brustumfang == brustumfang &&
other.armumfangRe == armumfangRe &&
other.armumfangLi == armumfangLi &&
other.oberschenkelumfangRe == oberschenkelumfangRe &&
other.oberschenkelumfangLi == oberschenkelumfangLi &&
other.bauchumfang == bauchumfang &&
other.hueftumfang == hueftumfang &&
other.wadenumfangRe == wadenumfangRe &&
other.wadenumfangLi == wadenumfangLi;
}
#override
int get hashCode =>
datum.hashCode ^
gewicht.hashCode ^
koerperfett.hashCode ^
muskelanteil.hashCode ^
halsumfang.hashCode ^
schulterumfang.hashCode ^
brustumfang.hashCode ^
armumfangRe.hashCode ^
armumfangLi.hashCode ^
oberschenkelumfangRe.hashCode ^
oberschenkelumfangLi.hashCode ^
bauchumfang.hashCode ^
hueftumfang.hashCode ^
wadenumfangRe.hashCode ^
wadenumfangLi.hashCode;
}
I have already checked the table of the database but it looks good.

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),
),
),
);
}
}

Flutter bloc_pattern returning NoSuchMethodError

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.

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