im currently having an issue using a package, the basic function it does it uploads and image and bring backs the url of the image, im not having issues uploading images (i printed the info) but whenever i do the return to bring back the information to my actual app it just brings back null.
The first code is where i call the function to upload the image and bring it back and also it eventually ataches it to another function, this part is found in the actual app.
File file, OnCreatePetEvent event, Emitter<PetState> emit) async {
PetsRepository repository = PetsRepository();
try {
ImageFileModel fileModel = await repository.putImage(file);
print(fileModel.toJson());
fileModel.toJson();
event.petModel.image = fileModel.data.imageKey;
event.petModel.thumbnail = fileModel.data.thumbnailKey;
repository.createPet(event.petModel);
} catch (e) {
throw e;
}
}
The second code is the function where i upload the image and eventually returns it, as previously said it does upload it and sends back data, this part is found in the package.
final apiProvider = Api.instance;
await apiProvider.postFile('upload_image', file, true).then((value) async {
dynamic json = jsonDecode(await value.stream.bytesToString());
print(json);
print(json['message']);
if (value.statusCode == 200) {
ImageFileModel filesURLs = ImageFileModel.fromJson(json);
print(filesURLs.toJson());
return filesURLs;
} else {
return json['message'];
}
}).catchError((e) {
print('error uploading file: ${e}');
});
}
ImageModel
//
// final imageFileUiModel = imageFileUiModelFromJson(jsonString);
import 'dart:convert';
ImageFileModel imageFileModelFromJson(String str) =>
ImageFileModel.fromJson(json.decode(str));
String imageFileModelToJson(ImageFileModel data) => json.encode(data.toJson());
class ImageFileModel {
ImageFileModel({
required this.message,
required this.data,
});
String message;
Data data;
factory ImageFileModel.fromJson(Map<String, dynamic> json) => ImageFileModel(
message: json["message"],
data: Data.fromJson(json["data"]),
);
Map<String, dynamic> toJson() => {
"message": message == null ? null : message,
"data": data == null ? null : data.toJson(),
};
}
class Data {
Data({
this.imageKey,
this.thumbnailKey,
});
String? imageKey;
String? thumbnailKey;
factory Data.fromJson(Map<String, dynamic> json) => Data(
imageKey: json["image_key"] == null ? null : json["image_key"],
thumbnailKey:
json["thumbnail_key"] == null ? null : json["thumbnail_key"],
);
Map<String, dynamic> toJson() => {
"image_key": imageKey == null ? null : imageKey,
"thumbnail_key": thumbnailKey == null ? null : thumbnailKey,
};
}
Console log
I/flutter (18011): success
I/flutter (18011): {message: success, data: {image_key: images/571221DTO.jpeg, thumbnail_key: images/53221fFX.jpeg}}
E/flutter (18011): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'Null' is not a subtype of type 'ImageFileModel'```
Related
I have a flutter application, which uses some server APIs.
When there is a successful response from the server, it would return json back:
{"success": true, "message": "success", "data": {"id": "21EE"} }
However, when there is failure, it would return:
{"success": false, "message": "failure"}
For more strict-typed use of flutter, I try to model the response.
Here is my try:
class ServerResponse {
final bool success;
final String message;
ServerResponse({
required this.success,
required this.message,
});
}
class _AuthAutenticationData {
final String id;
_AuthAutenticationData({
required this.id,
});
}
class AutoAuthenticateResponse extends ServerResponse {
final _AuthAutenticationData? data;
AutoAuthenticateResponse({
required success,
required message,
this.data,
}) : super(success: success, message: message);
}
Now, I have a function which calls a specific API:
Future<void> autoAuth() async {
final url = Uri.parse('${this._baseURL.toString()}/auto-auth');
try {
final response = await http.post(url, headers: {
'Authorization': 'SXXX',
});
print(response.body);
final AutoAuthenticateResponse responseBody = json.decode(response.body);
if (responseBody.success) {
return setUser(new User(id: responseBody.data!.id));
}
setUser(null);
} catch (error) {
print(error);
setUser(null);
}
}
Some code is irrelevant, but bottom line is that I receive the following error in the line: final AutoAuthenticateResponse responseBody = json.decode(response.body);:
I/flutter (14139): type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'AutoAuthenticateResponse'
I guess my solution is bad. Any advice how to fix it?
Well, you can use nullsafety feature for this. Since it's only if when the failure the data is not being returned.
{"success": true, "message": "success", "data": {"id": "21EE"} }
you can use this :
https://meruya-techhnology.github.io/json-to-dart/
Then the result will be a 2 class
class YourClass {
final bool success;
final String message;
final Data? data;
YourClass({this.success, this.message, this.data});
factory YourClass.fromJson(Map<String, dynamic> json) => YourClass(
success : json['success'],
message : json['message'],
data : json['data'] != null ? new Data.fromJson(json['data']) : null;
);
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['success'] = this.success;
data['message'] = this.message;
if (this.data != null) {
data['data'] = this.data.toJson();
}
return data;
}
}
And
class Data {
String id;
Data({this.id});
Data.fromJson(Map<String, dynamic> json) {
id = json['id'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
return data;
}
}
Then you can use it like this :
Future<void> autoAuth() async {
final url = Uri.parse('${this._baseURL.toString()}/auto-auth');
try {
final response = await http.post(url, headers: {
'Authorization': 'SXXX',
});
debugPrint(response.body);
final responseBody = YourClass.fromJson(response.body)
if (responseBody.success) {
return setUser(new User(id: responseBody.data!.id));
}
setUser(null);
} catch (error) {
print(error);
setUser(null);
}
}
another advice is use debugPrint instead of print, here you can read more : https://medium.com/flutter-community/debugprint-and-the-power-of-hiding-and-customizing-your-logs-in-dart-86881df05929
Use this link to generate models for your response
I have a model of Recipes and as the name suggests the model is for recipes. The recipe model has
name,
authorName,
category
List --> separate model
Lis --->separate model
And toJson and fromJson methods. Now I want a list which will be saved locally, the list will be of all the recipes the user has marked as favorite.
So, I made this FavoriteRecipeModel:
class FavoriteRecipeModel {
List<RecipeModel>? recipeList;
FavoriteRecipeModel({this.recipeList});
factory FavoriteRecipeModel.fromJson(Map<String, dynamic> json) =>
FavoriteRecipeModel(
recipeList: json["recipeList"] == null ? null : json["recipeList"],
);
Map<String, dynamic> toJson() => {
"recipe": recipeList == null ? null : recipeList,
};
}
And this is how the function is written:
FavoriteRecipeModel frm = FavoriteRecipeModel();
void addToFavorites() async {
await Hive.initFlutter();
var box = await Hive.openBox('favoriteRecipeList');
box.put('frm1', widget.recipe!);
print(frm);
}
The widget.recipe! is coming in like this:
final RecipeModel? recipe;
RecipeDetailsScreen({required this.recipe});
I'm using the recipe model to load all the data in the screen.
But I'm getting:
Unhandled Exception: HiveError: Cannot write, unknown type: RecipeModel. Did you forget to register an adapter?
What did I do wrong and how can I fix it?
Update 1: here's my full FavoritesModel
class FavoriteRecipeModel {
List<RecipeModel>? recipeList;
FavoriteRecipeModel({this.recipeList});
factory FavoriteRecipeModel.fromJson(Map<String, dynamic> json) =>
FavoriteRecipeModel(
recipeList: json["recipeList"] == null ? null : json["recipeList"],
);
Map<String, dynamic> toJson() => {
"recipe": recipeList == null ? null : recipeList,
};
}
class FavoriteAdapter extends TypeAdapter<FavoriteRecipeModel> {
#override
final typeId = 0;
#override
FavoriteRecipeModel read(BinaryReader reader) {
return FavoriteRecipeModel();
}
#override
void write(BinaryWriter writer, FavoriteRecipeModel obj) {
// TODO: implement write
writer.write(obj.recipeList);
}
}
and here's the method that should list the all recipe's selected as favorite:
FavoriteRecipeModel frm = FavoriteRecipeModel();
void addToFavorites() async {
Hive.registerAdapter(FavoriteAdapter());
await Hive.initFlutter();
var box = await Hive.openBox<FavoriteRecipeModel>('favoriteRecipeList');
box.put('frm1', FavoriteRecipeModel());
print(box.values);
}
It's in the hive docs, as you are trying to serialize a custom object Hive does not know how to do that. In which case you should create and register a TypeAdapter.
What i am trying to do is i am trying to catch the dio output.
Right now i am trying to create an article with flutter future functions.
Here are my codes:
Flutter
Future<dynamic> futureArticle;
String articleid;
futureArticle = CreateArticle(user.id, caption.text)
Dio Post Function
CreateArticleImage(String author,String caption,) async {
try {
FormData formData = new FormData.fromMap({
'author' : author.toString(),
'caption' : caption,
});
Response response = await Dio().post("$SERVER_IP/api/articlecreate/", data: formData);
print(response.toString());
} catch (e) {
print(e);
}
}
Json output
{
"id": "6ce0f013-d1fe-4f9f-bb72-0f1c8d21f64f",
"caption": "Caption",
},
What i am trying to do is i want to catch the id and return it to flutter as articleid.
Does anybody know how to?
When consuming an API, it's recommended to create a Class based on the data we expect to receive:
class Article {
String id;
String caption;
Article({
this.id,
this.caption,
});
}
Since we're using an API that returns JSON objects, we can implement a toJson function and a fromJson factory:
class Article {
String id;
String caption;
Article({
this.id,
this.caption,
});
factory Article.fromJson(Map<String, dynamic> json) => new Article(
id: json["id"] == null ? null : json["id"],
caption: json["caption"] == null ? null : json["caption"],
);
Map<String, dynamic> toJson() => {
"id": id == null ? null : id,
"caption": caption == null ? null : caption,
};
}
By doing so, we can create an Article class from the HTTP response:
FormData formData = new FormData.fromMap({
'author' : author.toString(),
'caption' : caption,
});
Response response = await Dio().post("$SERVER_IP/api/articlecreate/", data: formData);
print(response.toString());
final jsonData = json.decode(response.body);
Article article = Article.fromJson(Map<String, String>.from(jsonData));
The following snippet wraps a full example based on the scenario you specified:
import 'dart:convert';
void getArticle(var user, var caption) async {
Future<dynamic> futureArticle;
String articleid;
futureArticle = await createArticle(user.id, caption.text);
print(futureArticle.id);
print(futureArticle.caption);
articleid = futureArticle.id;
}
Future<Article> createArticleImage(String author,String caption,) async {
try {
FormData formData = new FormData.fromMap({
'author' : author.toString(),
'caption' : caption,
});
Response response = await Dio().post("$SERVER_IP/api/articlecreate/", data: formData);
print(response.toString());
final jsonData = json.decode(response.body);
Article article = Article.fromJson(Map<String, String>.from(jsonData));
return article;
} catch (e) {
print(e);
}
}
class Article {
String id;
String caption;
Article({
this.id,
this.caption,
});
factory Article.fromJson(Map<String, dynamic> json) => new Article(
id: json["id"] == null ? null : json["id"],
caption: json["caption"] == null ? null : json["caption"],
);
Map<String, dynamic> toJson() => {
"id": id == null ? null : id,
"caption": caption == null ? null : caption,
};
}
I am fetching the details from database and then I am parsing the json value. Below is the code for http request.
Future <List> getData() async{
if(endofrecord == false){
try{
var body = { "uid" : dtguid, "deviceid": deviceid, "offset": offset};
var url = 'http://192.168.1.100:8080/get_recommended.php';
// Starting Web API Call.
var response = await http.post(url, body: json.encode(body)).timeout(Duration(seconds: 5),
onTimeout: (){
// throw Exception();
_showSnackBar(context,'Some issue with connectivity. Can not reached to server.',Colors.redAccent);
//or you can also
return null;
});
if(response.statusCode == 200){
final data = parsedataFromJson(response.body);
setState(() {
recommended = true;
_inProcess = false;
if(data.count == null){
count = 0;
}else{
offset = offset + 5;
print(offset);
count = data.count;
}
if(data.content.length > 0 && data.content[0].name != 'Empty'){
for (var i in data.content) {
lists.add(i);
}
}else{
nodata = 'No Record Found';
endofrecord = true;
_showSnackBar(context,nodata,Colors.redAccent);
}
});
print(lists.length);
}
}catch(e){
print("Exception Caught: $e");
_showSnackBar(context,'Some issue with connectivity. Could not connect to server.',Colors.redAccent);
}
return lists;
}else{
return null;
}
}
Here is the JSON parsing.
import 'dart:convert';
DatabyPrice databyPriceFromJson(String str) => DatabyPrice.fromJson(json.decode(str));
class DatabyPrice {
DatabyPrice({
this.count,
this.content,
this.success,
});
int count;
List<Content> content;
bool success;
factory DatabyPrice.fromJson(Map<String, dynamic> json) => DatabyPrice(
count: json["count"],
content: List<Content>.from(json["content"].map((x) => Content.fromJson(x))),
success: json["success"],
);
}
class Content {
Content({
this.name,
this.uid,
this.pic,
this.state,
this.country,
this.lastLogin,
this.tabout,
this.averageOrating,
this.pricing,
});
String name;
int uid;
String pic;
String state;
String country;
String tabout;
String lastLogin;
String averageOrating;
List<Pricing> pricing;
factory Content.fromJson(Map<String, dynamic> json) => Content(
name: json == null ? 'Empty' : json["name"],
uid: json == null ? 0 :json["uid"],
pic: json == null ? 'Empty' :json["pic"],
state: json == null ? 'Empty' :json["state"],
tabout: json == null ? 'Empty' :json["tabout"],
country: json == null ? 'Empty' :json["country"],
lastLogin: json == null ? 'Empty' : json["last_login"],
averageOrating: json == null ? '0' :json["average_orating"],
pricing: List<Pricing>.from(json["pricing"].map((x) => Pricing.fromJson(x))),
);
}
class Pricing {
Pricing({
this.uid,
this.price,
this.serviceType,
});
int uid;
int price;
String serviceType;
factory Pricing.fromJson(Map<String, dynamic> json) => Pricing(
uid: json == null ? 0 :json["uid"],
price: json == null ? 0 :json["price"],
serviceType: json == null ? 'Empty' :json["service_type"],
);
}
Above code is working fine when there are some records returning from database but if there is no data or end of record then it is not working. I am getting below error.
I/flutter ( 5255): Receiver: null
I/flutter ( 5255): Tried calling: []("pricing")
I/flutter ( 5255): Exception Caught: NoSuchMethodError: The method '[]' was called on null.
How can I handle this situation when http request is not returning the data?
For converting the JSON into a PODO, you must use something like
JSON to Dart
Once the model is generated then it would be easy for you to check the null elements coming from the backend.
Did you catch any error in the try{} catch{} block.If your experiencing no errors check your custom JSON converter.Try testing without your custom JSON parsers and use the normal converter which converts JSON into a Map.If it still not working make sure you've import
the dart:async module like this import dart:asyncdart.If it doesn't change anything try using the .then() and .catch() syntax .If not try checking your backend database they may be something wrong
I need to fetch data from API
when I get the data I need to iterate through them
the problem is this API is structured like this :
{
"events": [
{
"image_url": "sun.jpg",
"name_ar": "sun",
"name_en": "sun"
},
{
"image_url": "sun.jpg",
"name_ar": "sun",
"name_en": "sun"
},
......
]
}
list of maps inside a map
this is my code
forEach only gives me a key and a value
the key isn't useful for me ..I am left with only the value
I need some sort of index
class Events with ChangeNotifier{
List<Event> _eventsList = [];
List<Event> get eventsList {
return [..._eventsList];
}
Future<void> fetchEvents(http.Client client) async {
try {
//fetch api
final response = await client.get(globals.apiUrl + '/events/');
// json.decode
final extractedData = json.decode(response.body) as Map<String, dynamic>;
final List<Event> loadedEvents = [];
//store events into a List<Event>
extractedData.forEach((key,eventData) {
print(key);//evnts
print(eventData);//this gives the list of maps
loadedEvents.add(Event(
name_en: eventData[0]['name_en'],
name_ar: eventData[0]['name_ar'],
image_url: eventData[0]['image_url'],
));
});
_eventsList = loadedEvents;
//for the provider
notifyListeners();
} catch (error) {
throw (error);
}
}
}
//Event class
class Event with ChangeNotifier {
final String image_url;
final String name_ar;
final String name_en;
Event({this.image_url, this.name_ar, this.name_en});
}
of course, this results in only the first event item
There is no need to iterate the loop just use https://app.quicktype.io/ to generate the model class for your response and use like below
// To parse this JSON data, do
//
// final eventsResponse = eventsResponseFromJson(jsonString);
import 'dart:convert';
EventsResponse eventsResponseFromJson(String str) => EventsResponse.fromJson(json.decode(str));
String eventsResponseToJson(EventsResponse data) => json.encode(data.toJson());
class EventsResponse {
List<Event> events;
EventsResponse({
this.events,
});
factory EventsResponse.fromJson(Map<String, dynamic> json) => EventsResponse(
events: json["events"] == null ? null : List<Event>.from(json["events"].map((x) => Event.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"events": events == null ? null : List<dynamic>.from(events.map((x) => x.toJson())),
};
}
class Event {
String imageUrl;
String nameAr;
String nameEn;
Event({
this.imageUrl,
this.nameAr,
this.nameEn,
});
factory Event.fromJson(Map<String, dynamic> json) => Event(
imageUrl: json["image_url"] == null ? null : json["image_url"],
nameAr: json["name_ar"] == null ? null : json["name_ar"],
nameEn: json["name_en"] == null ? null : json["name_en"],
);
Map<String, dynamic> toJson() => {
"image_url": imageUrl == null ? null : imageUrl,
"name_ar": nameAr == null ? null : nameAr,
"name_en": nameEn == null ? null : nameEn,
};
}
and replace you API call with below
Future<void> fetchEvents(http.Client client) async {
try {
//fetch api
final response = await client.get(globals.apiUrl + '/events/');
final List<Event> loadedEvents = new List();
//store events into a List<Event>
EventsResponse eventResponse = eventsResponseFromJson(response.body);
loadedEvents.addAll(eventResponse.events);
//for the provider
notifyListeners();
} catch (error) {
throw (error);
}
}
You can pull out the 'events' value from the map explicitly and then iterate over the events in that list. You'll need to cast with as List to see it as a List<dynamic> and then call .cast<Map<String, dynamic>>() to see it as a List<Map<String, dynamic>>;
final extractedData = jsonDecode(response.body) as Map<String, dynamic>;
final encodedEvents = (extractedData['events'] as List).cast<Map<String, dynamic>>();
final loadedEvents = [
for(final event in encodedEvents)
Event(
name_en: event['name_en'],
name_ar: event['name_ar'],
image_url: eventData[0]['image_url'],
),
];