Flutter: response variable blank in http request - flutter

I am trying to create a profile page for my flutter app
Here is a snippet
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class MyProfile extends StatefulWidget {
#override
_MyProfileState createState() => _MyProfileState();
}
class _MyProfileState extends State<MyProfile> {
bool visible=false;
var postData=List();
var jsonData;
Future accountInfo()async{
var url ='http://192.168.0.107/get_account.php';
var response= await http.get(url);
var jsonData= json.decode(response.body);
setState(() {
postData=jsonData;
});
debugPrint(jsonData);
return jsonData;
}
#override
void initState(){
super.initState();
accountInfo();
}
However, the variables postData and jsonData are returned as null.
Value of postData=[]
The API is working perfectly, tried it with postman and also tried intercepting with a proxy tool.
I am getting a valid json response body. But the values are not passed onto jsonData or postData.
When I use postData inside a text widget i get this error:-
RangeError(index): Index out of Range: no indices are valid: 0

You defined two jsonData. That may be the reason. Also, set jsonData inside setState(), too. Try this:
var jsonData;
Future accountInfo()async{
setState(() {
visible=true;
});
var url ='http://192.168.0.107/get_account.php';
var response = await http.get(url);
setState(() {
jsonData = json.decode(response.body); // Here we changed!
postData = jsonData;
});

The solution is to define jsonData as
Map<String, dynamic> jsonData= jsonDecode(response.body);

Related

Flutter: How to fix setState() callback argument returned a Future error?

My goal is to do a simple BitcoinApp. I am trying to get a method that is in the MyHomePageState class to call a method that I have in another class. When I compile and click on the button to give me the bitcoin info of USD I get the error of setState() callback argument returned to Future. Any advice or alternative that you can suggest me? I'm new to Flutter and adjusting.Here is my code:
///This piece of code is located in MyHomePageState Class
BitcoinCurrency _bitcoin = BitcoinCurrency();
void _getUSDBitcoin(){
setState(() async{
_bitcoin.usdBitcoin();
});
}
///This is the class I have outside of MyHomePageState Class.
class BitcoinCurrency {
///Variables we want for the information
String _disclaimer = "N/A";
String _time = "N/A";
String _currencyBitcoin = "N/A";
///Getters for our variables
get disclaimer => _disclaimer;
get time => _time;
get currencyBitcoin => _currencyBitcoin;
///Methods()
void usdBitcoin() async{
var url = Uri.https('api.coindesk.com', '/v1/bpi/currentprice.json');
var response = await http.get(url);
var httpBody = response.body;
var decoded = json.decode(httpBody);
_disclaimer = decoded['disclaimer'];
_time = decoded['time']['updated'];
_currencyBitcoin = decoded['bpi']['USD']['rate'];
}
}
You can convert usdBitcoin void method to Future<void>
Future<void>? usdBitcoin() async{
var url = Uri.https('api.coindesk.com', '/v1/bpi/currentprice.json');
var response = await http.get(url);
var httpBody = response.body;
var decoded = json.decode(httpBody);
_disclaimer = decoded['disclaimer'];
_time = decoded['time']['updated'];
_currencyBitcoin = decoded['bpi']['USD']['rate'];
}
And call setState like
usdBitcoin().then((value) => setState(() {}));
setState can't be an async function. usdBitcoin has to be a Future method, so you have to call it before the setState starts.
usdBitcoin method:
Future usdBitcoin() async{
var url = Uri.https('api.coindesk.com', '/v1/bpi/currentprice.json');
var response = await http.get(url);
var httpBody = response.body;
var decoded = json.decode(httpBody);
_disclaimer = decoded['disclaimer'];
_time = decoded['time']['updated'];
_currencyBitcoin = decoded['bpi']['USD']['rate'];
}
In initState:
usdBitcoin().then(
(value) => setState(
() {
},
),
)

I can't get data open weather map

I don't know why but keeps telling me error 400 when it tries to fetch data from open weather map
even i tried to change the api key and tried to change the code it self but it didn't work
so i want to know why this happening and i want to know the solution for this problem
import 'package:clima/services/location.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
const apiKey = '*****53a8**************';
class LoadingScreen extends StatefulWidget {
#override
_LoadingScreenState createState() => _LoadingScreenState();
}
class _LoadingScreenState extends State<LoadingScreen> {
double lontitude;
double latitude;
#override
void initState() {
getLocation();
getData();
super.initState();
}
Future getLocation() async {
Location location = Location();
await location.getCurrentLocation();
latitude = location.latitude;
lontitude = location.lontitude;
}
Future getData() async {
http.Response response = await http.get(
Uri.parse(
'https://api.openweathermap.org/data/2.5/weather?lat=$latitude&lon=$lontitude&appid=$apiKey'),
);
if (response.statusCode == 200) {
String data = response.body;
var temperature = jsonDecode(data)['main']['temp'];
print(temperature);
var condition = jsonDecode(data)['weather'][0]['id'];
print(condition);
var city = jsonDecode(data)['name'];
print(city);
} else {
print(response.statusCode);
}
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
Just typing in that URL in a browser and substituting longitude, latitude, and apiKey with values works just fine for me.
https://api.openweathermap.org/data/2.5/weather?lat=50,123123&lon=13.123123&appid=************** // add private key
OUTPUT:
{"coord":{"lon":13.1231,"lat":50.1231},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01n"}],"base":"stations","main":{"temp":281.16,"feels_like":279.56,"temp_min":279.08,"temp_max":283.95,"pressure":1023,"humidity":79},"visibility":10000,"wind":{"speed":2.57,"deg":250},"clouds":{"all":0},"dt":1632954450,"sys":{"type":2,"id":47765,"country":"CZ","sunrise":1632978356,"sunset":1633020533},"timezone":7200,"id":3061350,"name":"Žlutice","cod":200}
You should check the format of the things that get substituted by your code.

Flutter GetX controller getting null instead of data

I have an API (which does work and returns a response, and I even can see the response 1 line above the return statement), but for some reason, when the data should be passed to the variable, I receive null, instead of the returned value.
the service DOES return data I DO get the value from the API, at least it shows that there is data in the variable before the return.
The resp variable, which should contain the data, shows that the value is empty.
api_service.dart <= Returns a value
import 'dart:io';
import 'package:http/http.dart' as http;
import 'dart:convert';
class RemoteServices {
static var client = http.Client();
static Future sendImageForAnalysis(String filename) async {
var request =
http.MultipartRequest('POST', Uri.parse("http://10.0.2.2:8000/api"));
request.files.add(http.MultipartFile('picture',
File(filename).readAsBytes().asStream(), File(filename).lengthSync(),
filename: filename.split("/").last));
var res = await request.send();
if (res.statusCode == 200) {
http.Response.fromStream(res)
.then((response) {
var dataAsJson = json.decode(response.body);
/* The variable from above does have data, it's not empty and none of the errors appears*/
return dataAsJson;
})
.catchError((error) => print('Something went wrong')) /* Error is not showing */
.whenComplete(() => print('Got data from the server'));
} else {
/* Code does not get here */
return {'name': 'x'};
}
}
}
controller_results.dart <= Shows null, instead of the value.
import 'package:face_search/services/api_service.dart';
import 'package:get/get.dart';
class ResultsController extends GetxController {
final data = {}.obs;
final name = ''.obs;
void getItemData(imagePath) async {
var resp = await RemoteServices.sendImageForAnalysis(imagePath);
print(resp); /* This is empty for some reason */
if (resp != null) {
data.value = resp;
}
}
}
You're missing a return before http.Response.fromStream(res).
Does the result of the api return json? If its return json why dont try to create a model for it and call the list on your controller so that you can freely know if its having a data to return.

Flutter - Call API Rest

I have 3 .dart files: The Model, the API Call and the view. View call to the service to retrieve data, like this.
Model
class MapData {
String calle;
String pais;
String poblacion;
String postal;
String provincia;
MapData({
this.calle,
this.pais,
this.poblacion,
this.postal,
this.provincia,
});
factory MapData.fromJson(Map<String, dynamic> json) => new MapData(
calle: json["results"][0]['address_components'][1]["long_name"],
pais: json["results"][0]['address_components'][5]["long_name"],
poblacion: json["results"][0]['address_components'][2]["long_name"],
postal: json["results"][0]['address_components'][6]["long_name"],
provincia: json["results"][0]['address_components'][3]["long_name"],
);
}
Service
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:datameter/models/mapData_model.dart';
class DatameterService {
static Future<MapData> getMapData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final response = await http
.get(
'https://maps.google.com/maps/api/geocode/json?latlng=' +
"43.321146" +
',' +
"-3.008724" +
'&key=KEY",
)
.catchError((error) {
print(error.toString());
});
var responseJson = json.decode(response.body);
if (responseJson != null) {
final responseJson = json.decode(response.body);
return MapData.fromJson(responseJson);
}
return null;
}
}
Main view
void initState() {
print(DatameterService.getMapData()); //This doesn´t work
super.initState();
}
The problem: I don´t know how can i get the data.
So: What is the rigth way to get api call data?
You are trying to print a future!
Maybe try this:
void initState() {
DatameterService.getMapData().then((map){
print(map);
});
super.initState();
}
In the initstate you cannot await for future to complete but you can do something when it completes with the keyword "then".

I want to execute a function when the Flutter app starts

I want to send an ID to the server and receive json when the app is launched.
Flow
1.Start my app (Show splash screen)
2.Json request to server
3.If there is data, display page1. If not, display page2
it seems you my need to get a bit more learning about Flutter, my sugest is to start with this one only 10 euros will give you base from where will be easier to learn the rest, that said, to get a databse i'm using this code:
//lib/services/networking_service.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class NetworkHelper {
final String json;
final url = 'HERE YOU CAN PUT YOUR API URL';
NetworkHelper(this.json);
Map<String, String> headers = {
"Content-type": "application/x-www-form-urlencoded"
};
Future getData(BuildContext context) async {
http.Response response = await http.post(url, body: json, headers: headers);
if (response.statusCode == 200) {
Map<String, dynamic> decodedResp = jsonDecode(response.body);
print(decodedResp);
return decodedResp;
} else {
print(response.statusCode);
return null;
}
}
}
You can call it from your main like this:
static getCategories(BuildContext context) async {
String json =
'q={"f":"listCategories","Store_id":"$storeId","LANG":"$lang","UID":"$uid"}';
//THIS json VARIABLE IS WHERE YOU NEED TO PUT YOUR API CALL LÓGIC TO GET THAT ID, I LEAVE THIS FOR YOUR BETTER UNDERSTANDING
NetworkHelper networkHelper = NetworkHelper(json);
var decodedResp = await networkHelper.getData(context);
final CategoriesModel respData = CategoriesModel.fromJson(decodedResp);
print(respData);
//HERE YOU MAY RETURN O STORE IN PROVIDER YOUR RESPONSE AND SEND THE USER TO THE PAGE YOU CONSIDER
}
If you need more help I'm happy to help, but consider taking the course o learn a bit more, it will be lots more easy and enjoyable after.
use SchedulerBinding it runs when page is opened and widgets are build.
#override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
// your code after page opens,splash keeps open until work is done
});
}
#override
void initState() {
super.initState();
Timer(
Duration(seconds: 3),// you can do your stuff here when splash screen run
() => Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (BuildContext context) => LoginScreen())));}
and please put this code into the spalsh screen