Flutter HTTP Post Request does not reach Node-RED on Raspberry Pi - flutter

I am trying to send data from Flutter to Node-RED (to Raspberry Pi) over HTTP (not HTTPS). The URL http://bierbrauserver.ddns.net is from NO-IP (DDNS). The transfer to a test server from a Youtube Tutorial works fine. But when I change the URL from "https://reqres.in/api/users" to "http://bierbrauserver.ddns.net:1880" I get no input in the debug window of Node-RED. I tried in the AndroidManifest.xml to add the entry
so that http is allowed, but that didn't solve the problem either.
Furthermore I checked the port forwarding in the WLAN router configuration of the network where the Raspberry Pi is located. Here a port forwarding of HTTP and 1880 (Node-RED) was configured. The connection of the IP addresses should be ok, because I can access a database from an external port, which is also located on the Raspberry Pi. Can it be that only httpS post requests are possible ?
Future<UserModel> createUser(String name, String jobTitle)async{
const String Url = "https://reqres.in/api/users";
// const String Url = "https://bierbrauserver.ddns.net:1880";
final response = await http.post(Uri.parse(Url),body:
{
"name": name,
"job": jobTitle
});
if (response.statusCode == 201) {
final String responseString = response.body;
return userModelFromJson(responseString);
}
else
{
print(response.statusCode);
return UserModel(name:'Fail',job: 'Fail', id: 'Fail', createdAt: DateTime.now());
}
}
Thank you for your help.

The problem is solved. The program code has already been modified because I forgot to answer the question immediately when the problem was fixed. The problem was hidden in the Node-RED program. The wrong Node was selected in Node-RED.
The URL was extended with "/test", which is reused in Node-RED in the "http in" node. Now everything works fine.
For your information: "Zutat_1", "Zutat_2", "Zutat_3" and "Zutat_4" are global variables in this program and therefore do not have to be passed to the "createRezept" function.
Additionally, it should be mentioned that some elements in the code that do not belong to the English language are executed in the German language.
Future<RezeptModel> createRezept()async{
const String Url = "http://bierbrauserver.ddns.net:1880/test";
final response = await http.post(Uri.parse(Url),body:
{
"zutat1": Zutat_1.toStringAsFixed(2),
"zutat2": Zutat_2.toStringAsFixed(2),
"zutat3": Zutat_3.toStringAsFixed(2),
"zutat4": Zutat_4.toStringAsFixed(2),
"createdAt" : DateTime.now().toIso8601String()
});
if (response.statusCode == 201) {
final String responseString = response.body;
return rezeptModelFromJson(responseString);
}
else
{
print(response.statusCode);
return RezeptModel(zutat1:"Fehler",zutat2: "Fehler", zutat3: "Fehler", zutat4: "Fehler",createdAt: DateTime.now());
}
}
Here is the code which is used for parsing.(This is in a separate file, which in my case is named "Rezept_model.dart" )
import 'dart:convert';
RezeptModel rezeptModelFromJson(String str) => RezeptModel.fromJson(json.decode(str));
String rezeptModelToJson(RezeptModel data) => json.encode(data.toJson());
class RezeptModel {
RezeptModel({
required this.zutat1,
required this.zutat2,
required this.zutat3,
required this.zutat4,
required this.createdAt,
});
String zutat1;
String zutat2;
String zutat3;
String zutat4;
DateTime createdAt;
factory RezeptModel.fromJson(Map<String, dynamic> json) => RezeptModel(
zutat1: json["zutat1"],
zutat2: json["zutat2"],
zutat3: json["zutat3"],
zutat4: json["zutat4"],
createdAt: DateTime.parse(json["createdAt"]),
);
Map<String, dynamic> toJson() => {
"zutat1": zutat1,
"zutat2": zutat2,
"zutat3": zutat3,
"zutat4": zutat4,
"createdAt": createdAt.toIso8601String(),
};
}
For completeness here is the whole code of the main program.
import 'dart:convert';
import 'dart:math';
import 'package:bier_brau_project/variables.dart';
import 'package:bier_brau_project/rezept_model.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Bier Brau App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'HTTP Test Site'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
Future<RezeptModel> createRezept()async{
const String Url = "http://bierbrauserver.ddns.net:1880/test";
final response = await http.post(Uri.parse(Url),body:
{
"zutat1": Zutat_1.toStringAsFixed(2),
"zutat2": Zutat_2.toStringAsFixed(2),
"zutat3": Zutat_3.toStringAsFixed(2),
"zutat4": Zutat_4.toStringAsFixed(2),
"createdAt" : DateTime.now().toIso8601String()
});
if (response.statusCode == 201) {
final String responseString = response.body;
return rezeptModelFromJson(responseString);
}
else
{
print(response.statusCode);
return RezeptModel(zutat1:"Fehler",zutat2: "Fehler", zutat3: "Fehler", zutat4: "Fehler",createdAt: DateTime.now());
}
}
class _MyHomePageState extends State<MyHomePage> {
RezeptModel _rezept = RezeptModel(zutat1: "init", zutat2: "init", zutat3: "init",zutat4: "init", createdAt: DateTime.now());
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MySlider(Min:22.0,Max:40.0,Devisions: 100,unit:'l',title: 'Wasser',ID:1),
MySlider(Min:4.0,Max:20.0,Devisions: 100,unit:'kg',title:'Malz',ID: 2,),
MySlider(Min:60.0,Max:300.0,Devisions: 100,unit:'g',title:'Hopfen',ID: 3,),
MySlider(Min:12.0,Max:60.0,Devisions: 100,unit:'g',title:'Hefe',ID:4),
const SizedBox(height:32.0,),
Text( "Wasser "+ _rezept.zutat1 +"\n"
+"Malz "+_rezept.zutat2 +"\n"
+"Mopfen "+ _rezept.zutat3 +"\n"
+"Hefe "+ _rezept.zutat4 +"\n"
+"ist Erfolgreich übertragen worden "
+ _rezept.createdAt.toIso8601String())
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: ()async{
final RezeptModel rezept= await createRezept();
setState(() {
_rezept=rezept;
});
},
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
/// This is the stateful widget that the main application instantiates.
class MySlider extends StatefulWidget {
MySlider({Key? key,required this.Min, required this.Max,required this.Devisions,required this.unit,required this.title,required this.ID}): super(key: key);
final double Min;
final double Max;
final String unit;
final String title;
final int Devisions;
final int ID;
bool ValueChanged= false;
#override
State<MySlider> createState() => _MySliderState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MySliderState extends State<MySlider> {
double _currentSliderValue =0;
#override
Widget build(BuildContext context) {
return Padding (
padding: const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 16.0),
child: Column(children: <Widget> [
Text(
widget.title,
style: const TextStyle(
color: Colors.black54,
height: 1,
fontSize: 18
),
),
Slider(
value: widget.ValueChanged== false ? ((widget.Max-widget.Min)/2)+widget.Min : _currentSliderValue,
min: widget.Min,
max: widget.Max,
divisions: widget.Devisions,
label: _currentSliderValue.toStringAsFixed(2),
onChanged: (double value) {
setState(() {
_currentSliderValue = value;
first_call = false;
widget.ValueChanged =true;
switch(widget.ID) {
case 1: {Zutat_1 =double.parse(value.toStringAsFixed(2));}
break;
case 2: {Zutat_2 =double.parse(value.toStringAsFixed(2));}
break;
case 3: {Zutat_3 =double.parse(value.toStringAsFixed(2));}
break;
case 4: {Zutat_4 =double.parse(value.toStringAsFixed(2));}
break;
default: {}
break;
}
});
},
),
Text(
(widget.ValueChanged== false ?((widget.Max-widget.Min)/2)+widget.Min : _currentSliderValue.toStringAsFixed(2)).toString() + ' '+widget.unit,
),
])
);
}
}
Many thanks to all those who have dealt with this problem.
Here are still two images deposited around the connections to clarify.
Node-RED program to receive from http post
Android Studio emulator with the test application

Change your code to this:
final response = await http.post(Uri.parse(Url),body:
{
"name": name,
"job": jobTitle
});
if (response.statusCode == 201) {
final responseString = jsonDecode(_res.body)
return userModelFromJson(responseString);
}
else
{
print(response.statusCode);
return UserModel(name:'Fail',job: 'Fail', id: 'Fail', createdAt: DateTime.now());
}
}

Related

Please how do i resolve the exception of null is not a subtype of String of type cast

I created a web service from Beeceptor to use to update my UI but resulted in an exception of null is not a subType of String of type cast.Please i need help
import 'package:my_api_practice/Endpoint/endpoint.dart';
import 'dart:convert';
import 'package:http/http.dart'as http;
import 'UserDetails.dart';
import '';
part 'User.g.dart';
class User{
String? name;
String? imageUrl;
String? time;
List<UserDetails>?details;
User({required this.details,required this.name,required this.imageUrl,required this.time});
factory User.fromJson(Map<String,dynamic>json)=>_$UserFromJson(json);
User.blank()
:name='',
imageUrl='',
time='',
details=[];
static Future <List<User>>firstApi()async{
http.Response response=await http.get(Uri.parse("https://xcompany.free.beeceptor.com/api/v1/users"));
List<User>jsonitem=[];
if(response.statusCode!=200){
print(response.body);
}
for(var newItems in json.decode(response.body)){
jsonitem.add(User.fromJson(newItems));
}
return jsonitem;
}
}
<!--this is part of the User class-->
import 'package:my_api_practice/Endpoint/endpoint.dart';
import 'dart:convert';
import 'package:http/http.dart'as http;
import 'UserDetails.dart';
import '';
part 'User.g.dart';
class User{
String? name;
String? imageUrl;
String? time;
List<UserDetails>?details;
User({required this.details,required this.name,required this.imageUrl,required this.time});
factory User.fromJson(Map<String,dynamic>json)=>_$UserFromJson(json);
User.blank()
:name='',
imageUrl='',
time='',
details=[];
static Future <List<User>>firstApi()async{
http.Response response=await http.get(Uri.parse("https://xcompany.free.beeceptor.com/api/v1/users"));
List<User>jsonitem=[];
if(response.statusCode!=200){
print(response.body);
}
for(var newItems in json.decode(response.body)){
jsonitem.add(User.fromJson(newItems));
}
return jsonitem;
}
}
<!--this is my webservice-->
[{
"0":{
"name":"Emmanuel Armoo",
"imageUrl":"https://www.pexels.com/photo/man-smiling-behind-wall-220453/",
"time":"2:00",
"description":"The is an ancient geek priest who discovered the whole fact to unlease the new technological advancement"
},
"1":{
"name":"Emmanuel Armoo",
"imageUrl":"https://www.pexels.com/photo/man-smiling-behind-wall-220453/",
"time":"2:00",
"description":"The is an ancient geek priest who discovered the whole fact to unlease the new technological advancement"
},
"3":{
"name":"Sister Armoo",
"imageUrl":"https://www.pexels.com/photo/man-smiling-behind-wall-220453/",
"time":"2:00",
"description":"The is an ancient geek priest who discovered the whole fact to unlease the new technological advancement"
},
"4":{
"name":"Kofi Armoo",
"imageUrl":"https://www.pexels.com/photo/man-smiling-behind-wall-220453/",
"time":"2:00",
"description":"The is an ancient geek priest who discovered the whole fact to unlease the new technological advancement"
}
}]
<!--this is my list of widget UI-->
import 'package:my_api_practice/models/User.dart';
import 'package:flutter/material.dart';
class UserList extends StatefulWidget{
createState()=>_UserList();
}
class _UserList extends State<UserList> {
bool isWaiting = false;
List<User>users = [];
void initState(){
super.initState();
ApiData();
}
ApiData() async {
isWaiting=true;
var jsonItem = await User.firstApi();
setState(() {
users = jsonItem;
isWaiting=false;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('UserList'),
),
body: Column(
children: [
isWaiting ? LinearProgressIndicator(
value: null,
backgroundColor: Colors.grey,
valueColor: AlwaysStoppedAnimation<Color>(Colors.black),
) : Container(
child:Text('No UI to load')
),
Expanded(
child: ListView.builder(
itemCount: users.length,
itemBuilder: _itemTiles,)
)
],
),
);
}
Widget _itemTiles(BuildContext context, int index) {
return ListTile(
leading: _listImages(context, this.users[index]),
title: _listTitles(context, this.users[index]),
trailing: _listTimes(context, this.users[index]),
);
}
Widget _listImages(BuildContext context, User user) {
return ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Image.network(user.imageUrl!)
);
}
Widget _listTitles(BuildContext context, User user) {
return Text(user.name!);
}
Widget _listTimes(BuildContext context, User user) {
return Text(user.time!);
}
}
You try to parse the response as if it's of the form
[{
"name": "Emmanuel Armoo",
"imageUrl": "https://www.pexels.com/photo/man-smiling-behind-wall-220453/",
"time": "2:00",
"description": "The is an ancient geek priest who discovered the whole fact to unlease the new technological advancement"
},
...
]
But it's
[{
"0": {
"name": "Emmanuel Armoo",
"imageUrl": "https://www.pexels.com/photo/man-smiling-behind-wall-220453/",
"time": "2:00",
"description": "The is an ancient geek priest who discovered the whole fact to unlease the new technological advancement"
},
...
}]
I think you might be able to fix it by replacing
for(var newItems in json.decode(response.body)){
with
for(var newItems in json.decode(response.body)[0].values){
Although if possible I would fix the response to have it return like the first form
ADDITION:
I tried recreating a complete working app from your code and this is what I came up with, which seems to work fine:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const MaterialApp(home: UserList()));
}
class UserList extends StatefulWidget {
const UserList({super.key});
#override
State<UserList> createState() => _UserList();
}
class _UserList extends State<UserList> {
bool isWaiting = false;
List<User> users = [];
#override
void initState() {
super.initState();
apiData();
}
apiData() async {
isWaiting = true;
var jsonItem = await User.firstApi();
setState(() {
users = jsonItem;
isWaiting = false;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('UserList'),
),
body: Column(
children: [
isWaiting
? const LinearProgressIndicator(
value: null,
backgroundColor: Colors.grey,
valueColor: AlwaysStoppedAnimation<Color>(Colors.black),
)
: const Text('No UI to load'),
Expanded(
child: ListView.builder(
itemCount: users.length,
itemBuilder: _itemTiles,
))
],
),
);
}
Widget _itemTiles(BuildContext context, int index) {
return ListTile(
leading: _listImages(context, users[index]),
title: _listTitles(context, users[index]),
trailing: _listTimes(context, users[index]),
);
}
Widget _listImages(BuildContext context, User user) {
print(user.imageUrl);
return ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(30)),
child: Image.network(user.imageUrl!));
}
Widget _listTitles(BuildContext context, User user) {
return Text(user.name!);
}
Widget _listTimes(BuildContext context, User user) {
return Text(user.time!);
}
}
class User {
String? name;
String? imageUrl;
String? time;
User({required this.name, required this.imageUrl, required this.time});
factory User.fromJson(Map<String, dynamic> json) {
return User(
name: json['name'], imageUrl: json['imageUrl'], time: json['time']);
}
User.blank()
: name = '',
imageUrl = '',
time = '';
static Future<List<User>> firstApi() async {
http.Response response = await http
.get(Uri.parse("https://xcompany.free.beeceptor.com/api/v1/users"));
List<User> jsonitem = [];
if (response.statusCode != 200) {
print(response.body);
}
for (var newItems in json.decode(response.body)[0].values) {
jsonitem.add(User.fromJson(newItems));
}
return jsonitem;
}
}
It has some clean up and I removed some warnings from your code but I didn't change anything drastically and it seems to work fine. Except that I changed factory User.fromJson(Map<String,dynamic>json)=>_$UserFromJson(json); simply because I didn't have the implementation of _$UserFromJson. Also I noticed that your User mentions a List<UserDetails>?details; which I don't see in the api response so I just left that out. Notice also that the images don't work but that is simply because the imageUrl in your response doesn't link directly to an image but to a website with an image. Maybe this code helps you to find your actual problem because I don't think I can help anymore than this.

Sometimes variable changes, sometimes it doesn't

first of all, sorry for the lack of information in the title, I just couldn't think of anything better to write.
My problem is that I'm parsing JSON data from an online API and sometimes it displays what I want it to display, and sometimes it doesn't... here is the code:
(The first code block is the class of what I'll be using in the second block, which is the important part and probably where I think the problem is coming from)
import 'dart:convert';
import 'package:http/http.dart' as http;
class CanteenInfo {
final String canteenUrl = 'https://sigarra.up.pt/feup/pt/mob_eme_geral.cantinas';
List canteenMenu = [];
var data;
String workingHours = "yes";
CanteenInfo() {
getWebsiteData();
}
Future getWebsiteData() async {
var response = await http.get(Uri.parse(canteenUrl));
if (response.statusCode == 200) {
data = json.decode(response.body);
workingHours = data[3]["horario"];
print("Hours: " + workingHours);
}
else {
throw Exception('Failed to read $canteenUrl');
}
}
}
class WorkingHours extends StatefulWidget {
const WorkingHours({Key? key}) : super(key: key);
#override
State<WorkingHours> createState() => _WorkingHours();
}
class _WorkingHours extends State<WorkingHours> {
String hours = "yes";
CanteenInfo canteen = CanteenInfo();
void getHours() {
setState(() {
hours = canteen.getHours();
});
}
#override
Widget build(BuildContext context) {
getHours();
return Scaffold(
appBar: AppBar(
title: Text('EasyFood'),
),
body: Center(
child: Container (
margin: const EdgeInsets.only(top: 100),
child: Column(
children: <Widget>[
Text(
'Lunch: ' + hours,
style: const TextStyle(
fontSize: 20
)
),
],
),
),
),
);
}
}
If I haven't made my problem clear, when I run the code, sometimes it displays the text as "Lunch: yes" and sometimes as the correct thing, which is "Lunch: 11:30 às 14:00".
By my understanding, I think what's happening is that sometimes the code can get the API information and time and has time to change the variable before the page loads, and sometimes it doesn't. Either way, I don't know how to fix it so if anyone has any idea I would relly appreciate the help :)
Thanks alot for taking the time to read this
I'm not sure if getHours method exists in CanteenInfo.
But you probably need to override initState method in your stateful widget and call
canteen.getWebsiteData().then((value) {
setState(() => hours = canteen.workingHours);
});
or something like that depending on which method returns data from API
A good decision will be to wait CanteenInfo object "canteen" to be initialized, smth like this:
var flag = false;
loadData()async{
flag = true;
canteen = CanteenInfo();
await getHours();
setState((){flag=false;});
}
Widget build(BuildContext context) {
if (hours == "yes" && !flag)
loadData();
if (flag)
return Scaffold(body:CircularProgressIndicator());
return Scaffold(
appBar: AppBar(
title: Text('EasyFood'),
),
body: Center(
child: Container (
margin: const EdgeInsets.only(top: 100),
child: Column(
children: <Widget>[
Text(
'Lunch: ' + hours,
style: const TextStyle(
fontSize: 20
)
),
],
),
),
),
);
}
I'm not sure if class object initialization works correct here, maybe you also need to add async/await
class CanteenInfo {
final String canteenUrl = 'https://sigarra.up.pt/feup/pt/mob_eme_geral.cantinas';
List canteenMenu = [];
var data;
String workingHours = "yes";
getWebsiteData() async {
var response = await http.get(Uri.parse(canteenUrl));
if (response.statusCode == 200) {
data = json.decode(response.body);
workingHours = data[3]["horario"];
print("Hours: " + workingHours);
}
else {
throw Exception('Failed to read $canteenUrl');
}
}
getHours() {
return workingHours;
}
}
// ------------------------
class WorkingHours extends StatefulWidget {
const WorkingHours({Key? key}) : super(key: key);
#override
State<WorkingHours> createState() => _WorkingHours();
}
// ------------------------
class _WorkingHours extends State<WorkingHours> {
String hours = "yes";
CanteenInfo canteen = CanteenInfo();
#override
void initState() {
super.initState();
canteen.getWebsiteData().then(() {
hours = canteen.getHours();
});
}
}

Flutter unspecific Error while triggering an API request with Switch on/off events

I want to control raspberry pins with a flutter app. Therefore I build an API with Python Flask. In this case, I want to turn on and off a light with a Switch in Flutter. When the switch is toggled, I want a request to be triggered telling the API to turn the light on or off.
Switch:
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
bool lampStatus = false;
void toggleSwitch(bool value) async{
if (lampStatus == false) {
bool lampenstatus = await lampon();
setState(() {
lampStatus = lampenstatus;
});
print('Lights on');
} else {
setState(() {
lampStatus = false;
});
print('Lights off');
// await lampoff();
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
Container(child: Text('Lights are ${lampStatus==true? 'on': 'off'}')),
Switch(
value: lampStatus,
onChanged: toggleSwitch,
activeTrackColor: Colors.lightGreenAccent,
activeColor: Colors.green,
),
],
),
),
);
}
}
Future<bool> lampon() async {
final response =
await http.post(Uri.http(url, '/lampon'));
if (response.statusCode == 200) {
final bool lampenstatus = json.decode(response.body);
print(lampenstatus);
return lampenstatus;
} else {
return false;
}
}
Future lampoff() async {
final response =
await http.post(Uri.http(url, '/lampoff'));
if (response.statusCode == 200) {
return true;
} else {
return null;
}
}
With this switch and both functions (I've tried both with lampon) I can send my request to the API and the light goes on, but then the following error occurs and my Flutter app crashes:
unawaited(xhr.onError.first.then((_) {
// Unfortunately, the underlying XMLHttpRequest API doesn't expose any
// specific information about the error itself.
completer.completeError(
ClientException('XMLHttpRequest error.', request.url),
StackTrace.current);
}));
Does somebody have a solution for it?
Here is my PythonCode:
from flask import Flask, jsonify, request
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.OUT)
app = Flask(__name__)
#app.route('/lampon', methods=['GET','POST'])
def lamp_on():
GPIO.output(23, GPIO.HIGH)
return jsonify({'Lampenstatus':True})
#app.route('/lampoff', methods=['GET','POST'])
def lamp_off():
GPIO.output(23, GPIO.LOW)
return jsonify({'Lampenstatus':False})
if __name__ == '__main__':
app.run(host='0.0.0.0')

How to solve the "Type Null is not a subtype of type ..." error?

When I run the code below, it prints this error to the screen, and I don't know why:
type Null is not a subtype of type int
This is my model class for the data from the API:
class data {
final int id;
final String email;
final String first_name;
final String last_name;
final String avatar;
data({
required this.id,
required this.email,
required this.first_name,
required this.last_name,
required this.avatar,
});
factory data.fromJson(Map<String, dynamic> json) {
return data(
id: json['id'],
email: json['email'],
first_name: json['first_name'],
last_name: json['last_name'],
avatar: json['avatar'],
);
}
}
API calling part(this part is the calling):
import 'dart:async';
import 'dart:convert';
import 'package:api_data/models/datamodel.dart';
import 'package:http/http.dart' as http;
class ApiManager {
Future<data> fetchAlbum() async {
final response =
await http.get(Uri.parse('https://reqres.in/api/users?page=2'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return data.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
}
Main part
import 'package:api_data/models/datamodel.dart';
import 'package:api_data/network/api_data.dart';
import 'package:flutter/material.dart';
class Testpage extends StatefulWidget {
const Testpage({Key? key}) : super(key: key);
#override
_TestpageState createState() => _TestpageState();
}
class _TestpageState extends State<Testpage> {
late Future<data> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = ApiManager().fetchAlbum();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Test2'), centerTitle: true),
body: Center(
child: FutureBuilder<data>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.email.toString());
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
),
);
}
}
I don't understand why this doesn't work properly.
You are running with Null Safety enabled in your project. You have declared your all fields required and non-null in your Data Model Class.
Your API response is having a field absent or having a null value, that's why you are facing this issue.
Solution: Replacing int with int? (making fields optional will resolve issue).
You can use the Helper class.
class TypesHelper{
static int toInt(num val){
try{
if(val == null){
return 0;
}
if(val is int){
return val;
}else{
return val.toInt();
}
}catch(error){
print('Error');
return 0;
}
}
Then you force conversion to int.
On your Model class
id: TypesHelper.toInt(json['id']),
It appears to me that some of your json response might not have an id , so it's showing the error . You should check the json response you are getting and see if it has the id .

issue with flutter concatenation

I have a problem concatenating two variables on flutter : I can't concatenate them, when I try to add a string behind, it doesn't work.
class MusicAlbumListing extends StatefulWidget {
final albumName;
MusicAlbumListing({Key key, this.albumName}) : super(key: key);
#override
_MusicAlbumListing createState() => _MusicAlbumListing();
}
class _MusicAlbumListing extends State<MusicAlbumListing> {
String _albumName = '';
void initState() {
_albumName = widget.albumName.toString();
var strr = "Look this new album : $_albumName ! Awesome :)";
}
It returns
Look this new album : Mothership
And then nothing
Can anyone help me ?
I don't think there is anything wrong with your String concatenation.
Here is a Minimal Working Example based on your incomplete code snippet:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'StackOverflow Answer',
home: MusicAlbumListing(albumName: 'Mothership'),
);
}
}
class MusicAlbumListing extends StatefulWidget {
final String albumName;
MusicAlbumListing({Key? key, required this.albumName}) : super(key: key);
#override
_MusicAlbumListing createState() => _MusicAlbumListing();
}
class _MusicAlbumListing extends State<MusicAlbumListing> {
String _albumName = '';
void initState() {
super.initState();
_albumName = "Look this new album : ${widget.albumName} ! Awesome :)";
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text(_albumName)),
);
}
}
Provide your Minimal Working Example for a more targeted answer.
Thanks for your fast reply
First i fetch on a local server (my raspberry pi) a file called output.txt with ssh script
import 'package:flutter/material.dart';
import 'package:ssh/ssh.dart';
import 'album_music.dart';
class MainMenu extends StatefulWidget {
#override
_MainMenu createState() => _MainMenu();
}
class _MainMenu extends State<MainMenu> {
String _result = '';
List _array;
final pi = new SSHClient(
host: "192.168.0.35",
port: 22,
username: "pi",
passwordOrKey: "mysecret",
);
Future<void> exec(String sshScript) async {
String result;
try {
result = await pi.connect();
if (result == "session_connected") {
result = await pi.execute(sshScript);
pi.disconnect();
}
} catch (e) {
print('Error: ${e.code}\nError Message: ${e.message}');
}
setState(() {
_result = result;
_array = null;
});
}
#override
void initState() {
super.initState();
exec(
"cd ../../; cd var/www/html/music; ls -d */ > output.txt; cat output.txt");
}
#override
Widget build(BuildContext context) {
final title = 'Albums disponibles';
var strings = _result.split('\n');
print(strings);
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: ListView(
children: new List.generate(
strings.length - 1,
(index) => new ListTile(
title: Text(strings[index],
style: TextStyle(fontWeight: FontWeight.w500)),
leading: Icon(Icons.folder_open),
trailing: Icon(Icons.forward),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MusicAlbumListing(
albumName: strings[index].replaceAll("/", ""))));
},
),
)),
),
);
}
I open the txt file, and transform the cat output.txt to an array.
I think you're right, maybe the problem is not the concatenation.
For the first loop, Daft_Punk goes well.
That's my txt file :
Daft_Punk
MotherShip
LeonardCohenBestSongs
Pink_Floyd_Essentials
I have : Look this new album : Daft_Punk ! Awesome :)
But second loop and those after, concatenation won't work
Maybe a "bad" character has been introduced, which prevents concatenation