how to convert _InternalLinkedHashMap to list object in dart - dart

I have recieved some data from server side, and it parsed as LinkedHashMap by default, now I want to convert LinkedHashMap to List<Oject>, this is the code I am using now:
var articles = result["list"];
List<String> genreIdsList = new List<String>.from(articles);
var items = genreIdsList.map((String str)=>Item.fromJson(str)).toList();
but it did not work as expect. Shows this error:
/flutter (10074): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'
E/flutter (10074): #0 new List.from (dart:core-patch/array_patch.dart:40:5)
E/flutter (10074): #1 Repo._getArticles (package:cruise/src/common/repo.dart:82:39)
E/flutter (10074): <asynchronous suspension>
E/flutter (10074): #2 Repo.getArticles (package:cruise/src/common/repo.dart:27:12)
E/flutter (10074): <asynchronous suspension>
E/flutter (10074): #3 initArticles (package:cruise/src/page/home/components/homelistdefault_component/effect.dart:42:25)
E/flutter (10074): <asynchronous suspension>
This is the result data:
and this is my fromJson:
factory Item.fromJson(String str) => Item.fromMap(json.decode(str));
what should I do to parse the LinkedHashMap to List<Item>?

try this
List articles = result["list"];
List<Item> items = [];
articles.forEach((element) {
Item item = Item.fromMap(element as Map<String, dynamic>);
items.add(item);
});

Now I parse it like this:
List articles = result["list"];
List<Item> items = List.empty(growable: true);
articles.forEach((element) {
HashMap<String,Object> map = HashMap.from(element);
Item item = Item.fromMap(map);
items.add(item);
});
return items;

Related

How to implement `assert()` for Type / T

to reproduce:
create an empty project
paste the code below in main.dart
press f5 (in vs code, else just run the app)
note that dartpad ignores assert
class Foo<T> {
Foo(this.data) : assert(T is int || T is String);
final T data;
}
void main() {
print('hello');
final _fooInt = Foo<int>(1);
}
logs:
flutter: hello
[ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: 'package:type_test/main.dart': Failed assertion: line 2 pos 27: 'T is int || T is String': is not true.
#0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:46:39)
#1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:36:5)
#2 new Foo
package:type_test/main.dart:2
#3 main
package:type_test/main.dart:8
#4 _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:136:25)
#5 _rootRun (dart:async/zone.dart:1186:13)
#6 _CustomZone.run (dart:async/zone.dart:1090:19)
How can I implement correctly the assertion on line 2?
Thank you
credit to Stampi from the answer on r/flutterDev discord
the change below fixes the issue
class Foo<T extends int> {
- Foo(this.data) : assert(T is int || T is String);
+ Foo(this.data) : assert(T == int || T == String);
final T data;
}
void main() {
print('hello');
final _fooInt = Foo<int>(1);
print(_fooInt.data.runtimeType);
}
Dart JS backend treats ints as double. That's why your code doesn't throw an exception. You can read about it here.
Added. You can try something like this:
class Foo<T> {
Foo(this.data) : assert(T == int || T == String);
final T data;
}
void main() async {
print('hello');
// ok
final _fooInt = Foo<int>(1);
// ok
final _fooStr = Foo<String>("Str");
// fails
final _fooDouble = Foo<double>(5.5);
}

Saving and loading, shared preferences

List<double> timersValuesList = [30.0, 60.0, 90.0, 120.0, 150.0, 180.0];
void saveSharedPreferences() async {
// from List of double to a List of String
List<String> convertedTimerValues = timersValuesList.map((i) => i.toString()).toList();
// getting the instance of sharedPreferences as Object prefs
SharedPreferences prefs = await SharedPreferences.getInstance();
// taking my List as key of "mylist", if it doesn't exist create empty List, this is List of String
List<String> myList = (prefs.getStringList('mylist') ?? List<String>());
//saving the List of String as key"mylist"
await prefs.setStringList('mylist', convertedTimerValues);
}
void loadSharedPreferences() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> myList = (prefs.getStringList('mylist') ?? List<String>());
List<double> myOriginalList = myList.map((i)=> double.parse(i)).toList();
timersValuesList = myOriginalList;
// print('Your list $myOriginalList');
}
I tried to use SharedPreferences in this file for saving and loading a List of 6 double values, which are used in other widget and could be modified. Now the problem is that everytime I open my app it doesn't make me see updated and modified values, but always the first one I declared for default. For example. I edit my first value and it becomes like this.
timersValuesList[0] = 35
then I save it and exit the app. When I relaunch the app it shows me values of 30 not 35 like it should be. But if I edit for example with a +1, it jumps directly to 36 so it makes me thing that value was saved but was not visualized correctly at first launch. After that adding values work correctly. Can someone help me? I cannot find a way to do this. Maybe I should put in the saving function the default values in case doesn't exist any file saved already? thanks help with code of saving and loading a list of double too, because I don't think I'm doing it well. Thanks again.
I made this. ( I could call in the initState any async function so I called an external one). But i get error: "NoSuchMethodError: The method "[]" was called on null.
Receiver: null
Tried calling: "
class _SettingsPageState extends State<SettingsPage> {
List<double> timersList;
#override initState() {
super.initState();
callLoad();
}
Future callLoad() async {
timersList = await loadTimers();
}
void saveTimers(List<double> timersList) async {
List<String> convertedTimerValues = timersList.map((i) => i.toString()).toList();
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setStringList('TimerList', convertedTimerValues);
}
Future<List<double>> loadTimers() async {
List<double> defaultTimersList = [30.0, 60.0, 90.0, 120.0, 150.0, 180.0];
List<double> savedTimerList;
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> myList = prefs.getStringList('TimerList');
if (myList == null ){
return defaultTimersList;
} else{
savedTimerList = myList.map((i)=> double.parse(i)).toList();
return savedTimerList;
}
}
I edit like your code suggest. But I get this error, but the screen been loads with the correct value.
I/flutter ( 9290): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 9290): The following RangeError was thrown building SettingsPage(dirty, dependencies: [MediaQuery], state:
I/flutter ( 9290): _SettingsPageState#c0ade):
I/flutter ( 9290): RangeError (index): Invalid value: Valid value range is empty: 0
I/flutter ( 9290): When the exception was thrown, this was the stack:
I/flutter ( 9290): #0 List.[] (dart:core-patch/growable_array.dart:145:60)
I/flutter ( 9290): #1 _SettingsPageState.build (package:my_fitness_tools/pages/settings_page.dart:175:45)
I/flutter ( 9290): #2 StatefulElement.build (package:flutter/src/widgets/framework.dart:3825:27)
I/flutter ( 9290): #3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3739:15)
I/flutter ( 9290): #4 Element.rebuild (package:flutter/src/widgets/framework.dart:3565:5)
I/flutter ( 9290): #5 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3722:5)
I/flutter ( 9290): #6 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3864:11)
I/flutter ( 9290): #7 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3717:5)
I/flutter ( 9290): #8 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2961:14)
I/flutter ( 9290): #9 Element.updateChild (package:flutter/src/widgets/framework.dart:2764:12)
I/flutter ( 9290): #10 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4876:14)
I/flutter ( 9290): #11 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2961:14)
I/flutter ( 9290): #12 Element.updateChild (package:flutter/src/widgets/framework.dart:2764:12)
This is my Scaffold.
Scaffold(
appBar: new AppBar(
backgroundColor: Options.selectedTheme.primaryColorDark,
centerTitle: true,
title: Text("Settings"),
),
drawer: DrawerApp(),
body:
new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage("assets/backgrounds/Sfondo.jpg"),
fit: BoxFit.fill)),
),
ListView( // vertical listview
children: <Widget>[
//Inizio oggetti in ordine verticale della pagina.
SizedBox(
height: 10.0,
),
titleSettings("Timers"),
Container(
height: MediaQuery.of(context).size.height,
child: ListView( // horizontal Listview
shrinkWrap: true,
physics: ClampingScrollPhysics(),
scrollDirection: Axis.horizontal,
children: <Widget>[
timerColumn(timersList[0], 0), // line 175
timerColumn(timersList[1], 1),
timerColumn(timersList[2], 2),
timerColumn(timersList[3], 3),
timerColumn(timersList[4], 4),
timerColumn(timersList[5], 5),
],
),
),
],
)
Editing the List timersList = [0,0,0,0,0,0] fixed that.
But I have a question. If I want to use now those values in another file. I have made the same exact function for loading. But I get this error.
Same thing on declaring everything and function but why it wants to be static instead the file before didn't?
This is almost certainly to do with the order of execution. You need to look for the answer in the code that you haven't shown.
widget state created
[30.0, etc assigned to timersValueList
initState called, which presumably calls...
loadSharedPreferences called, but suspends awaiting getInstance, allowing...
framework calls build - shows current value (30)
getInstance completes, so loadSharedPreferences continues assigning [35.0, etc to timersValueList
nothing informs the widget that its state has changed until you do an update.
Add a call to setState at the end of loadSharedPreferences to inform the framework of the change.
void loadSharedPreferences() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> myList = prefs.getStringList('mylist') ?? ['30', '60', '90'];
List<double> myOriginalList = myList.map((i) => double.parse(i)).toList();
setState(() {
timersValuesList = myOriginalList;
});
}
Edit
I'd change your State to this:
class _SettingsPageState extends State<SettingsPage> {
List<double> timersList;
#override
initState() {
super.initState();
loadTimers();
}
saveTimers(List<double> timersList) async {
List<String> convertedTimerValues = timersList.map((i) => '$i').toList();
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setStringList('TimerList', convertedTimerValues);
}
loadTimers() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> myList = prefs.getStringList('TimerList');
setState(() {
timersList = (myList == null)
? [30.0, 60.0, 90.0, 120.0, 150.0, 180.0]
: myList.map((i) => double.parse(i)).toList();
});
}
#override
Widget build(BuildContext context) {
if (timersList == null) return Center(child: CircularProgressIndicator());
return Whatever(/* Fill me in with the normal page*/);
}
}
You need to assign to timersList inside a setState so that the framework knows that you've changed the state! This will cause it to rebuild the widget. Note, that in the build you have to cope with timersList being null. It being null indicates that you are still waiting for stuff to happen, so should render a placeholder.

how to properly implement click events on columns, fields and rows with PaginatedDataTable

I'm new to flutter and dart, so this is my first app (yay!!!)
in general I'm trying to create a table with two static rows of data. since I'm a beginner that what I've decided to start and play with :)
I use the PaginatedDataTable component for that, and I create a class that extends DataTableSource for the data source of the table.
the default rows per page is set to 10, so even when I have two rows of data it shows 2 rows and 8 empty rows, is that that the default behaviour ? probably not and I'm missing something :)
so when I click on an empty row I get an exception that onTap isn't being implemented on that row.
to make my question clearer this is my code:
this is my Widget function that returns the PaginatedDataTable component
Widget searchPageTable() {
int _rowsPerPage = PaginatedDataTable.defaultRowsPerPage;
final List<DataColumn> _columns = new List<DataColumn>();
_columns.add(new DataColumn(label: Text("col1"),onSort: onSort));
_columns.add(new DataColumn(label: Text("col2"),onSort: onSort));
_columns.add(new DataColumn(label: Text("col3"),onSort: onSort));
return new PaginatedDataTable(header: Text("header"),
columns: _columns,
rowsPerPage: _rowsPerPage,
source: new MyDataSource(),
);
}
so here in the columns I added the onSort() function (for now an empty function) but I know that I can catch when clicking on column titles and implement that properly. moving on..
my data source is implement with the following code;
class MyDataSource extends DataTableSource {
cellTapped() {
}
#override
DataRow getRow(int index) {
if (index == 0) {
final List<DataCell> row = new List<DataCell>();
row.add(new DataCell(Text("col1txt"),onTap: cellTapped));
row.add(new DataCell(Text("col2txt"),onTap: cellTapped));
row.add(new DataCell(Text("col3txt"),onTap: cellTapped));
return new DataRow(cells: row);
} else if (index == 1) {
final List<DataCell> row = new List<DataCell>();
row.add(new DataCell(Text("col1txt2"),onTap: cellTapped));
row.add(new DataCell(Text("col2txt2"),onTap: cellTapped));
row.add(new DataCell(Text("col3txt2"),onTap: cellTapped));
return new DataRow(cells: row);
} else {
return null;
}
}
#override
int get selectedRowCount {
return 0;
}
#override
bool get isRowCountApproximate {
return false;
}
#override
int get rowCount {
return 2;
}
}
so here for each row I create a DataRow and in it for each column a DataCell and I implement an onTap for each DataCell. but what if I wanna change the onTap for each row and not for specific columns, how an I do that ?
and whenever I click on an empty row, I get the following exception:
flutter: ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
flutter: The following NoSuchMethodError was thrown while handling a gesture:
flutter: The method 'call' was called on null.
flutter: Receiver: null
flutter: Tried calling: call(true)
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0 Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)
flutter: #1 DataTable.build.<anonymous closure> (package:flutter/src/material/data_table.dart:586:38)
flutter: #2 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:507:14)
flutter: #3 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:562:30)
flutter: #4 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
flutter: #5 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
flutter: #6 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:175:7)
flutter: #7 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
flutter: #8 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
flutter: #9 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
flutter: #10 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:180:19)
flutter: #11 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:158:22)
flutter: #12 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:138:7)
flutter: #13 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:101:7)
flutter: #14 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:85:7)
flutter: #15 _invoke1 (dart:ui/hooks.dart:168:13)
flutter: #16 _dispatchPointerDataPacket (dart:ui/hooks.dart:122:5)
flutter:
flutter: Handler: onTap
flutter: Recognizer:
flutter: TapGestureRecognizer#a6733(debugOwner: GestureDetector, state: possible, won arena, finalPosition:
flutter: Offset(209.0, 375.5), sent tap down)
flutter: ════════════════════════════════════════════════════════════════════════════════════════════════════
in general here I just want to ignore click events on empty row. how to implement that ?
any information regarding this issue would be appreciated.
thanks :)
You first question: "the default rows per page is set to 10, so even when I have two rows of data it shows 2 rows and 8 empty rows, is that that the default behaviour ? probably not and I'm missing something :)"
Yes, this is the expected behaviour because it will create the number of rows specified in rows per page property.
Your 2nd question: "whenever I click on an empty row, I get the following exception:..."
This is because in your getRow function it returns null when index > 1 so the exception is also expected. Practically, you don't want to hard-code your data source and set rows per page proportionally based on how many rows your data source has. For instance, if you know your data source will start with 100 rows, then you can either set each page having 10 or 20 rows. You should ideally avoid having empty rows in the page by dynamically building the page based on your data source update. But this exception is not going to crash your app and to some extent can be ignored if you want to simplify things.
Your final question about handling onTap of each row.
I am assuming you want to execute some actions to the selected row(s), for instance, you can enable/disable some buttons based on whether there is any row being selected. Note that there is an actions property (of type List<Widget>) on the PaginatedDataTable and you can put some buttons or other widgets you want. The way I did this is via passing in a event handler (such as onRowSelected which is simply a function taking no argument and returning nothing) into MyDataSource constructor and call it on onSelectedChanged handler within getRow function where you return a DataRow. This is an example of what I did to give you a specific idea:
class OrderSource extends DataTableSource {
int _selectedCount = 0;
final List<Order> _orders;
final Function onRowSelected;
OrderSource(this._orders, this.onRowSelected);
#override
DataRow getRow(int index) {
assert(index >= 0);
if (index >= _orders.length) return null;
final Order order = _orders[index];
return DataRow.byIndex(
index: index,
selected: order.selected,
onSelectChanged: (bool value) {
if (order.selected != value) {
_selectedCount += value ? 1 : -1;
assert(_selectedCount >= 0);
order.selected = value;
notifyListeners();
onRowSelected();
//print('selected rows: $selectedRowCount');
}
},
cells: <DataCell>[
DataCell(Text('${order.orderID}')),
DataCell(Text('${order.side}')),
...),
]);
}
}
Hope this helps.

Flutter: How to access a member in a static method in the same class

I have this class with a static method (to run a compute isolate)
class ResizeImage {
ResizeImage(this.tempPath) {
sTempPath = tempPath;
print('main()resizeMyProImage.dart...IN CLASS.........imgFile tempPath: '+tempPath);
print('main()resizeMyProImage.dart...IN CLASS.........imgFile sTempPath: '+sTempPath);
}
String tempPath;
static String sTempPath
....
static File decodeProfileImage(File imageFile) {
// get sTempPath here...
print('decodeProfileImage...decodeImage.dart...IN CLASS.......well.tempPath......hit with: '+sTempPath);
// Im.Image image = Im.decodeImage(imageFile.readAsBytesSync());
// Im.Image smallerImage = Im.copyResize(image, 150); // choose the size here, it will maintain aspect ratio
// return new File(sTempPath+'thumbnail.jpg')
// ..writeAsBytesSync(Im.encodeJpg(smallerImage, quality: 85));
}
I am instantiating like so in another class...
ResizeImage resizeImage = new ResizeImage(tempPath);
print('uploadFile >>>>>>>>>>>>>>>>>>>>>....hit begin 000 resizeImage.tempPath: '+resizeImage.tempPath);
File myFile;
if (isProfilePic) myFile = (await resizeImage.resizeMyProImage(file));
Error:
Isolate (389190561) 'main.dart:_spawn()' exited with an error
E/flutter ( 2369): [ERROR:flutter/shell/common/shell.cc(181)] Dart Error: Unhandled exception:
E/flutter ( 2369): Invalid argument(s)
E/flutter ( 2369): #0 _StringBase.+ (dart:core/runtime/libstring_patch.dart:246:57)
How do I access tempPath member from the static decodeProfileImage. -Thanks for reading.
EDIT:
This has now changed, callbacks can be static methods: see https://api.flutter.dev/flutter/foundation/ComputeCallback.html.
I haven't tried and I haven't found a related changelog. I hope the docs are correct.
Original
https://docs.flutter.io/flutter/foundation/compute.html
The callback argument must be a top-level function, not a closure or an instance or static method of a class.
note especially
not a ... or static method of a class
Future doSomethingInIsolate() async {
var result = await compute(decodeProfileImage, data);
}
File decodeProfileImage(File imageFile) {
var resize = ResizeImage();
resize...
}
class ResizeImage {
ResizeImage(this.tempPath) {
...
}
}

Dart mirrors issue. getField

I'm trying use mirrors, but I have error in some simple code.
import 'dart:mirrors';
// -----------------
class TestUser extends Object{
String name = 'aaa';
String status = 'bbb';
String position = 'ccc';
int age = 20;
}
var mapVal = new TestUser();
InstanceMirror mirror = reflect(mapVal);
var futureValue = mirror.getField('age');
futureValue.then((imValue) => print("Field: age = ${imValue.reflectee}"));
Result:
Unhandled exception:
Class 'String' has no instance getter '_name#0x1aab143'.
NoSuchMethodError : method not found: '_name#0x1aab143'
Receiver: "age"
Arguments: []
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:45)
#1 Symbol.getName (dart:_collection-dev/symbol.dart:64)
#2 _n (dart:mirrors-patch/mirrors_impl.dart:59)
#3 _LocalObjectMirror.getField (dart:mirrors-patch/mirrors_impl.dart:254)
#4 main (file:///C:/Users/Less/IdeaProjects/testDart/console/template.dart:67:36)
#5 _startIsolate.isolateStartHandler (dart:isolate-patch/isolate_patch.dart:216)
#6 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:115)
What it means? I have no idea. Why it takes '_name#0x1aab143' from String? Black magic...
var mapVal = new TestUser();
InstanceMirror mirror = reflect(mapVal);
// getField() expects an instance of Symbol, not String
var futureValue = mirror.getField(new Symbol("age"));
// getField() returns an InstanceMirror, not a Future<InstanceMirror>
print("Field: age = ${futureValue.reflectee}");
Could it be that you updated your SDK, but not your Editor? The current Editor with the current SDK shows all of that as a warning, making troubleshooting this code rather trivial.
Not everything in Dart is async ;-)
// mirror.getField('age');
InstanceMirror im = mirror.getField(#age); // needs a symbol
// futureValue.then((imVa
print("Field: age = ${im.reflectee}")); // getField doesn't return a future

Resources