Problem serializing a list of objects in flutter and saving it using shared preferences
Solution 1
this probably will solve your problem:
var contacts = decoded.map((c) => Contact.fromJson(Map<String, dynamic>.from(c)));
Solution 2
It took me a while to parse through these answers to get to a block of working code for serializing the Contacts returned from contacts_service.
I used json_serializable to generate the toJson methods, added them to the existing classes using extension, and used the json.encode @Silris posted.
Here's the working block of code:
import 'package:contacts_service/contacts_service.dart';
import 'dart:convert';
// Copied generated toJson methods
extension ContactToJson on Contact {
Map<String, dynamic> toJson() => <String, dynamic>{
'identifier': identifier,
'displayName': displayName,
'givenName': givenName,
'middleName': middleName,
'prefix': prefix,
'suffix': suffix,
'familyName': familyName,
'company': company,
'jobTitle': jobTitle,
'androidAccountTypeRaw': androidAccountTypeRaw,
'androidAccountName': androidAccountName,
'AndroidAccountType': androidAccountType,
'emails': emails?.map((item) => item.toJson()).toList(),
'phones': phones?.map((item) => item.toJson()).toList(),
'postalAddresses':
postalAddresses?.map((address) => address.toJson()).toList(),
'birthday': birthday?.toIso8601String(),
'avatar': avatar,
};
}
extension ItemToJson on Item {
Map<String, dynamic> toJson() => {
'value': value,
'label': label,
};
}
extension PostalAddressToJson on PostalAddress {
Map<String, dynamic> toJson() => <String, dynamic>{
'label': label,
'street': street,
'city': city,
'postcode': postcode,
'region': region,
'country': country,
};
}
serializeContacts(List<Contact> contacts) => json.encode(contacts.map((contact) => contact.toJson()).toList());
Using this with the supporting permissions and services in a button looks like:
onPressed: () async {
// Either the permission was already granted before or the user just granted it.
if (await Permission.contacts.request().isGranted) {
List<Contact> contacts = await ContactsService.getContacts(
withThumbnails: false, photoHighResolution: false);
// Imported from above file
print(serializeContacts(contacts));
}
},
Pressing this button in the iphone simulator will print:
[{"identifier":"F57C8277-585D-4327-88A6-B5689FF69DFE","displayName":"Anna Haro","givenName":"Anna","middleName":"","prefix":"","suffix":"","familyName":"Haro","company":"","jobTitle":"","androidAccountTypeRaw":null,"androidAccountName":null,"AndroidAccountType":null,"emails":[{"value":"[email protected]","label":"home"}],"phones":[{"value":"555-522-8243","label":"home"}],"postalAddresses":[{"label":"home","street":"1001 Leavenworth Street","city":"Sausalito","postcode":"94965","region":"CA","country":"USA"}],"birthday":"1985-08-28T00:00:00.000","avatar":null},{"identifier":"AB211C5F-9EC9-429F-9466-B9382FF61035","displayName":"Daniel Higgins Jr.","givenName":"Daniel","middleName":"","prefix":"","suffix":"Jr.","familyName":"Higgins","company":"","jobTitle":"","androidAccountTypeRaw":null,"androidAccountName":null,"AndroidAccountType":null,"emails":[{"value":"[email protected]","label":"home"}],"phones":[{"value":"555-478-7672","label":"home"},{"value":"(408) 555-5270","label":"mobile"},<…>
Anan Saadi
Updated on December 31, 2022Comments
-
Anan Saadi over 1 year
I have been trying to save a list of type
Contact
(which is a class fromcontacts_service
) package by serializing it usingtoJosn
andfromJson
and then saving it asString
inShared Preferences
to & fromJosn :
Contact.fromJson(Map<String, dynamic> json): identifier = json['identifier'], displayName = json['displayName'], givenName = json['givenName'], middleName = json['middleName'], prefix = json['prefix'], suffix = json['suffix'], familyName = json['familyName'], company = json['company'], avatar = json['avatar'], androidAccountType = json['androidAccountType'], jobTitle = json['jobTitle'], androidAccountTypeRaw = json['androidAccountTypeRaw'], androidAccountName = json['androidAccountName'], emails = json['emails'], phones = json['phones'], postalAddresses = json['postalAddresses'], birthday = json['birthday'];
Map<String, dynamic> toJson() => { 'identifier':identifier, 'displayName':displayName, 'givenName':givenName, 'middleName':middleName, 'prefix':prefix, 'suffix':suffix, 'familyName':familyName, 'company':company, 'avatar':avatar, 'jobTitle':jobTitle, 'androidAccountTypeRaw':androidAccountTypeRaw, 'androidAccountName':androidAccountName, 'emails':emails, 'phones':phones, 'postalAddresses':postalAddresses, 'birthday':birthday, 'androidAccountType':androidAccountType};
saving & loading:
void saveContacts() async{ SharedPreferences prefs = await SharedPreferences.getInstance(); final String List = json.encode(contacts.map((contact) => contact.toJson())); await prefs.setString('contactList', List); }
void loadConatcs() async{ SharedPreferences prefs = await SharedPreferences.getInstance(); final String saved = prefs.getString('contactList'); final List<dynamic> decoded = json.decode(saved); contacts = decoded.map((contact) => Contact.fromJson(contact)); }
but I am gettign an error
Converting object to an encodable object failed: Instance of 'MappedListIterable<dynamic, Item>'
also note that this is my first time trying to serialize and object so might have missed some things up in
to
&fromJosn
edit:
I also tried using
toEncodable
final String List = jsonEncode(contacts, toEncodable: (c)=> c.toJson());
but it would return an exception :
type 'MappedListIterable<dynamic, Contact>' is not a subtype of type 'List<Contact>'
-
Anan Saadi over 2 yearsthe problem above was when trying to encode, although it's my fault for not clarifying, anyway I solved it by using
toEncodeable
injosnDecode
but now I am gettingUnhandled Exception: type 'MappedListIterable<dynamic, Contact>' is not a subtype of type 'List<Contact>'
when decoding although I am using the code you provided above @Emre Akçadağ -
Emre Akçadağ over 2 yearsthis is my method to use jsonlist to modelList
static List<User>? fromJsonList(List? data) => data?.map((m) => m == null ? null : User.fromJson(Map<String, dynamic>.from(m))).toList();
hope it helps you. -
Anan Saadi over 2 yearsyou're code is returning
Converting object to an encodable object failed: Instance of 'MappedListIterable<dynamic, Item>
, I have also triedtoEncodable
to encode the list, like this:final String List = jsonEncode(contacts, toEncodable: (c)=> c.toJson() );
but it would return when loadingUnhandled Exception: type 'MappedListIterable<dynamic, Contact>' is not a subtype of type 'List<Contact>'
.@Things of N -
Rahul Vashishtha over 2 yearsPlease explain about how this code works and is helpful rather than just posting the code.
-
Vursin over 2 years@AnanSaadi I just updated dartpad example. Please give it a try and let me know the issue.
-
Anan Saadi over 2 yearsI have copied your code exactly yet still receiving the same error
Converting object to an encodable object failed: Instance of 'MappedListIterable<dynamic, Item>'
, I think the issue is that classContact
includes a list ofIterable
and type calledUint8List
, can you take a look at the full model and see if it needs something else in order to encode it ? @Things of N -
Vursin over 2 years@AnanSaadi I have updated the code that including
SubContact List
in Contact class. I think you have to refactor your code from using Iterable to List (which is extended from Iterable with a lot of benefit features). The code here -
Anan Saadi over 2 yearsCan you please explain what
SubContact
does and what should I do toemails
andphones
in order to get them working ? @Things of N -
Vursin over 2 yearsThe
SubContact
is similar toItem
orPostalAddress
in your script. I have seen a pull request that already refactored the code from using Iterable to List here. The way usingList<Item>
orList<PostalAddress>
is the same withList<SubContact>
. Please check it and let me know if it's usable or not. You can useiterable.toList()
to convert anyIterable
object toList
object. @AnanSaadi -
Vursin over 2 yearsI have updated the way to add the modified package to the current project.
-
Anan Saadi over 2 yearsHey, I didn't get the time to check your solution but I believe it's the correct answer so I have awarded you the bounty and will update you later on wither it has worked or not @Things of N
-
Anan Saadi over 2 yearsthanks for your answer, I wasn't able to make this work by my own and gave up, I'll check this solution later
-
Anan Saadi over 2 yearsYou might also want to do a pull request since the serializing method included in the package doesn't work
-
Assaf over 2 yearsHappy to help. I hope that it works for you. Someone opened an issue asking for serialization to be included in the package and it didn't get any traction github.com/lukasgit/flutter_contacts/issues/162. I'll post a link to this thread and see if they're interested in the contribution.