Can't retrieve more than one info from api in Flutter - flutter

I'm trying to fetch both temperature and icon name from Openweathermap api. The problem occurs when I try to to fetch icon(or rather icon name).
It returns an error :
Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
And I can't seem to find where the problem is. In other models I have other data types and it works fine, here it doesn't.
When I add icon to model, view returns null for temperature.
Here is code for weather model:
class WeatherData {
int? temp;
String? icon;
WeatherData({
this.temp,
this.icon
});
WeatherData.fromJson(dynamic json) {
var tempInKelvin = json["main"]["temp"];
temp = (tempInKelvin - 273.15).round();
icon = json["weather"]["icon"];
}
}
This is weather service:
class WeatherService {
final apiKey = "7e23369c183254302bda0471cc3f848c";
Future<WeatherData?> getWeatherForLocation(LocationData location) async {
WeatherData? weatherData;
var params = {
"lat": location.lat.toString(),
"lon": location.lon.toString(),
"city": location.city,
"appId": apiKey,
};
var url = Uri.http('api.openweathermap.org', '/data/2.5/weather', params);
Response response = await get(url);
if (response.statusCode == HttpStatus.ok) {
var jsonResponse = jsonDecode(response.body) as Map<String, dynamic>;
weatherData = WeatherData.fromJson(jsonResponse);
print("Request successful: $jsonResponse");
return weatherData;
} else {
print("Request failed with status: ${response.statusCode}");
return weatherData;
}
}
}
This is weather controller:
class WeatherController extends GetxController {
final WeatherService _weatherService = Get.find();
Rxn<LocationData> locationData = Rxn();
Rxn<WeatherData> weatherData = Rxn();
// RxString infoText = "...".obs;
String get address =>
"${locationData.value?.city},${locationData.value?.county}, ${locationData.value?.country}";
String get temperature => "${weatherData.value?.temp}";
// String get icon => "${weatherData.value?.icon}";
#override
void onInit() async {
super.onInit();
await getCurrentLocation();
await getTemperatureForCurrentLocation();
await getWeatherIcon();
}
getCurrentLocation() async {
LocationData? location = await _weatherService.getCurrentLocation();
print(location?.city);
locationData.value = location;
}
getTemperatureForCurrentLocation() async {
if (locationData.value != null) {
weatherData.value=
await _weatherService.getWeatherForLocation(locationData.value!);
// _getInfoText(weatherData.value?.temp);
}
}
}

Looking at their API docs, it seems that weather contains an array of objects (as a result, you need an integer index to figure out which one you want).
https://openweathermap.org/current
To fix it, you can simply opt to always use the first object in the weather array and take the icon/description from that:
"weather": [
{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01d"
}
],
Which is:
icon = json["weather"][0]["icon"];

Can you please check this:
var tempInKelvin = double.parse(json["main"]["temp"]);
or this if your number is integer:
var tempInKelvin = int.parse(json["main"]["temp"]);

Related

Get request of google maps api from postman is working properly but in the app it is showing null(NoSuchMethodError)

Why is the GET request to the Google Maps API working properly in Postman but showing a null error (NoSuchMethodError) when implemented in the app?
Environment
I've configured a local REST API:
static const String BASE_URL = "http://localhost:8000";
static const String GEOCODE_URI = "api/v1/config/geocode-api";
Code I'm Using
Here are the excerpts of the code I'm attempting this with.
The main implementation is in location_controller.dart:
<!-- location_controller.dart -->
import 'package:ecommerceapp/models/address_model.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get_connect/http/src/response/response.dart';
import 'package:get/get_state_manager/get_state_manager.dart';
import 'package:ecommerceapp/data/repositary/location_repo.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class LocationController extends GetxController implements GetxService {
LocationRepo locationRepo;
LocationController({
required this.locationRepo,
});
bool _loading = false;
late Position _position;
late Position _pickPosition;
Placemark _placemark = Placemark();
Placemark _pickPlacemark = Placemark();
List<AddressModel> _addressList = [];
late List<AddressModel> _allAddressList = [];
List<String> _addressTypelist = ["home", "office", "others"];
int _addressTypeIndex = 0;
late Map<String, dynamic> _getAddress;
late GoogleMapController _mapController;
List<AddressModel> get addressList => _addressList;
bool get loading => _loading;
Position get position => _position;
Position get pickPosition => _pickPosition;
Map get getAddress => _getAddress;
bool _updateAddressData = true;
bool _changeAddress = true;
void setMapController(GoogleMapController mapController) {
_mapController = mapController;
}
void updatePosition(CameraPosition position, bool fromAddress) async {
print("Update Position");
if (_updateAddressData) {
_loading = true;
update();
try {
if (fromAddress) {
_position = Position(
latitude: position.target.latitude,
longitude: position.target.longitude,
timestamp: DateTime.now(),
heading: 1,
accuracy: 1,
altitude: 1,
speedAccuracy: 1,
speed: 1,
);
} else {
_pickPosition = Position(
latitude: position.target.latitude,
longitude: position.target.longitude,
timestamp: DateTime.now(),
heading: 1,
accuracy: 1,
altitude: 1,
speedAccuracy: 1,
speed: 1,
);
}
if (_changeAddress) {
String _address = await getAddressfromGeocode(LatLng(position.target.latitude, position.target.longitude));
}
} catch (e) {
print(e);
}
}
}
Future<String> getAddressfromGeocode(LatLng latLng) async {
String _address = "Unknown Location Found";
print("Address : $_address");
Response response = await locationRepo.getAddressfromGeocode(latLng);
print("Status Code : ${response.statusCode}");
print(response.body);
if (response.body["status"] == "OK") {
_address = response.body["result"][0]['formatted_address'].toString();
print("Printing Address : $_address");
} else {
print("Error getting the google api");
}
return _address;
}
}
which calls the location_repo.dart:
import 'package:ecommerceapp/utils/app_constants.dart';
import 'package:get/get_connect/http/src/response/response.dart';
import 'package:google_maps_flutter_platform_interface/src/types/location.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:ecommerceapp/data/api/api_client.dart';
class LocationRepo {
final ApiClient apiClient;
final SharedPreferences sharedPreferences;
LocationRepo({
required this.apiClient,
required this.sharedPreferences,
});
Future<Response> getAddressfromGeocode(LatLng latLng) async {
return await apiClient.getData('${AppConstants.GEOCODE_URI}'
'?lat=${latLng.latitude}&lng=${latLng.longitude}');
}
}
In the getAddressfromGeocode method, when I tried to print the latitude and longitude, the print statements were also working fine:
Future<Response> getData(String uri, {Map<String, String>? headers}) async {
try {
Response response = await get(
uri,
headers: headers == null ? _mainHeaders : headers,
);
return response;
} catch (e) {
return Response(statusCode: 1, statusText: e.toString());
}
}
But, my code fails and response.body is null:
flutter: NoSuchMethodError: The method '\[\]' was called on null.
Receiver: null
Tried calling: \[\]("status")
I have no idea what I'm doing and still haven't asked ChatGTP, so I did not find any working solutions. Please help.

How to fetch data without retrieve to widgets in flutter?

In my code I want fetch data to backend without show in ui. Data getting from API, andaslo for that I use model class that same model and API call I used to fetch data and show in UI. That's work without any errors.But in this page I want get doctor_in vale is true or false from that same model and API call method.
model class
class DataDoctor {
String appId;
String channelName;
String receiver_name;
bool doctor_in;
DataDoctor(
{required this.appId,
required this.channelName,
required this.receiver_name,
required this.doctor_in});
factory DataDoctor.fromJson(Map<String, dynamic> json) {
return DataDoctor(
appId: json['appId'] == null ? null : json['appId'],
channelName: json['channelName'] == null ? null : json['channelName'],
receiver_name:
json['receiver_name'] == null ? null : json['receiver_name'],
doctor_in: json['doctor_in'] == null ? null : json['doctor_in'],
);
}
}
using this model I want get doctor_in boolean value
to the getDoctorActive() method
getDoctorActive() method
void getDoctorActive() {
Map<String, dynamic> jsonData =
json.decode(jsonDataAsString) as Map<String, dynamic>;
doctor_in.value = jsonData['doctor_in'].toString(); }
error
How to get data without show in UI in flutter?
API code
import 'dart:convert';
import 'package:http/http.dart';
import '../model/appIdModel.dart';
class ApiService {
loadData(String channelName) async {
final String url ='https://jsonplaceholder.typicode.com/posts/1=$channelName';
Future<List<Data>> getData() async {
Response response = await get(Uri.parse(url));
if (response.statusCode == 2000) {
Map<String, dynamic> json = jsonDecode(response.body);
List<dynamic> body = json['data'];
List<Data> datas = body.map((dynamic item) => Data.fromJson(item).toList();
return datas;
} else {
throw ('cannot fetch data');
}
}
}
}
initState
Timer? timer;
bool doctor_in = false;
#override
void initState() {
super.initState();
getDoctorActive();
timer =
Timer.periodic(Duration(seconds: 15), (Timer t) => checkDoctorActive());
}
checkDoctorActive
Future<void> checkDoctorActive() async {
if (doctor_in == true) {
future = client.getData(widget.channelName);
}
}
errors
API call
If you want to periodically fetch data in the background without updating the UI, you can create a class for that purpose, like this
class DoctorCheck{
Future<bool> isDoctorActive(String channelName) async {
// do the api call here as shown in the line below
// var jsonResponse = await client.getData(widget.channelName)
return Data.fromJson(jsonResponse).doctor_in == true;
}
}
And call it wherever you want, like this
bool isDoctorActive = await DoctorCheck().isDoctorActive(channelName);
It will return a bool whether the doctor is active or not.
Put it in a function like this
Future<void> dr() async {
bool isDrActive = await DoctorCheck().isDoctorActive(channelName);
setState(() { doctor_in = isDrActive; });
}
Whenever you call dr(), your variable doctor_in will be updated with the latest value of whether doctor is active or not.
From #rrttrr answer with a change
class DoctorCheck{
Future<bool> isDoctorActive(String channelName) async {
return Data.fromJson(json).doctor_in == true; // Change jsonResponse to json
}
}

Get Expected a value of type 'String', but got one of type 'Null' error when fetching some movie info from the MovieDB api

I tried a tutorial to create a movie application. It works fine to get popular movies but with the same code to get upcoming movies I got this error and UI doesn't show anything. The error is :
Expected a value of type 'String', but got one of type 'Null'
here is where error happens:
Future<List<Movie>> getPopularMovies({required int page}) async {
//we are going to get Response
Response _response =
await _http.request('/movie/popular', query: {'page': page});
if (_response.statusCode == 200) {
Map<String?, dynamic> _data = _response.data;
List<Movie> _movies = _data['results'].map<Movie>((_movieData) {
return Movie.fromJson(_movieData);
}).toList();
return _movies;
} else {
throw Exception('Couldn\'t get the popular movies');
}
}
Future<List<Movie>> getUpcomingMovies({required int page}) async {
//we are going to get Response
Response _response =
await _http.request('/movie/upcoming', query: {'page': page});
if (_response.statusCode == 200) {
Map<String?, dynamic> _data = _response.data;
List<Movie> _movies = _data['results'].map<Movie>((_movieData) {
return Movie.fromJson(_movieData);
}).toList();
return _movies;
} else {
throw Exception('Couldn\'t get the popular movies');
}
}
I tried jsonDecode(_response.data) but got the this error: Expected a value of type 'String', but got one of type '_JsonMap'
Maybe some particular field in your model class may receive null value from response...that's why flutter indicates error....
To avoid this you have to make the field nullable using (?)...
Example:
int? rank;
Inside constructor remove required keyword for that field.
Now it will accepts null values...
Can solve your problem
Future<List<Movie>> getUpcomingMovies({required int page}) async {
List<Movie> list = [];
Response _response = http
.request('/movie/upcoming', query: {'page': page})
.then((_response) {
setState(() {
var list = json.decode(_response.body);
//categories = list.map((category) => Category.fromJson(category)).toList();
if (list is List) {
Map<String?, dynamic> _data = _response.data;
List<Movie> _movies = _data['results'].map<Movie>((_movieData) {
return Movie.fromJson(_movieData);
}).toList();
return _movies;
}
else {
print('response is not list');
}
});
}
);
return list;
}

How to solve this List<dynamic> type error in Flutter/Dart

I am very new to flutter and dart. Trying to return a list from this future that pulls data from an api but I keep getting this error. Someone here helped me solve a similar error by casting to a list because I was calling map function on an array that returns an iterable but in this case here I'm not sure what needs to be done.
type List<dynamic> is not a subtype of type FutrueOr<ListCity>>
Data is received like below:
{
"data": {
"127287": {
"Feature_int_id": "127287",
"Admin1_str_code": "US06",
"Country_str_code": "US",
"Feature_str_name": "Acampo",
"Feature_dec_lat": "38.194",
"Feature_dec_lon": "-121.25"
},
"116496": {
"Feature_int_id": "116496",
"Admin1_str_code": "US06",
"Country_str_code": "US",
"Feature_str_name": "Acton",
"Feature_dec_lat": "34.49",
"Feature_dec_lon": "-118.22"
},
"124284": {
"Feature_int_id": "124284",
"Admin1_str_code": "US06",
"Country_str_code": "US",
"Feature_str_name": "Adelanto",
"Feature_dec_lat": "34.665",
"Feature_dec_lon": "-117.512"
},
}
Below is the code for future:
Future<List<City>> fetchCitiesByProvince(provinceCode) async {
final response = await http.get(Uri.https('localhost/msd', 'api/cities/' + provinceCode));
final responseJson = json.decode(response.body);
final dataMap = responseJson['data'];
if (response.statusCode == 200) {
List citiesList = [];
for (var city in dataMap.keys) {
if (dataMap[city]['Admin1_str_code'] == provinceCode) {
citiesList.add(
{
'cityCode': dataMap[city]['Feature_int_id'],
'cityName': dataMap[city]['Feature_str_name']
}
);
}
}
return citiesList;
} else {
throw Exception('Failed to load cities');
}
}
City Class:
class City {
final String cityCode;
final String cityName;
City({#required this.cityCode, #required this.cityName});
factory City.fromJson(Map<String, dynamic> json) {
return City(
cityCode: json['Feature_int_id'],
cityName: json['Feature_str_name']
);
}
}
You need to return List<City> in your method. So, change the following code:
List citiesList = [];
to
List<City> citiesList = [];
--- UPDATE ---
You need to user your City constructor or factory to generate the item from json like this:
City.fromJson(dataMap[city]);
// Or
City(cityCode: dataMap[city]['Feature_int_id'],
cityName: dataMap[city]['Feature_str_name']
);
Here the updated sample code:
Future<List<City>> fetchCitiesByProvince(provinceCode) async {
final response = await http.get(Uri.https('localhost/msd', 'api/cities/' + provinceCode));
final responseJson = json.decode(response.body);
final dataMap = responseJson['data'];
List<City> citiesList = [];
if (response.statusCode == 200) {
for (var city in dataMap.keys) {
if (dataMap[city]['Admin1_str_code'] == provinceCode) {
citiesList.add(City.fromJson(dataMap[city]));
}
}
} else {
throw Exception('Failed to load cities');
// either throwing an error or return empty list.
}
return citiesList;
}

Flutter: value of type 'Future<List<UserVideo>>' can't be assigned to a variable of type 'List<UserVideo>'

I am trying to use one List (custom type) but getting error.
When i try to use the getData() function. Like below.
List<UserVideo> videoDataList = [];
videoDataList = UserVideo.getData();
This is initState method.
#override
void initState() {
videoDataList = await UserVideo.getData();
WidgetsBinding.instance.addObserver(this);
_videoListController.init(
_pageController,
videoDataList,
);
super.initState();
}
I am getting the error.
A value of type 'Future<List<UserVideo>>' can't be assigned to a variable of type 'List<UserVideo>'.
Try changing the type of the variable, or casting the right-hand type to 'List<UserVideo>'.
Here is the code for function.
class UserVideo {
final String url;
final String image;
final String desc;
UserVideo({
this.url: mockVideo,
this.image: mockImage,
this.desc,
});
Future <List<UserVideo>> getData() async {
List<UserVideo> list = [];
try {
var deviceid = '123';
var dtgUid = '100';
var nodata;
var bodyss = {
"uid": dtgUid,
"deviceid": deviceid,
};
var url = 'http://192.168.100.4:8080/videos/get-data.php';
// Starting Web API Call.
var response = await http
.post(url, body: json.encode(bodyss))
.timeout(Duration(seconds: 5), onTimeout: () {
return null;
});
if (response.statusCode == 200) {
final data = StreamingFromJson(response.body);
if (data.count == null) {
count = 0;
} else {
count = data.count;
}
if (data.content.length > 0 && data.content[0].name != 'Empty') {
for (var i in data.content) {
list.add(UserVideo(image: i.thumbnail, url: i.video, desc: i.title));
}
} else {
nodata = 'No Record Found';
}
print(list.length);
}
} catch (e) {
print("Exception Caught: $e");
}
return list;
}
Edit:
Just showing the hardcoded value which is working fine.
static List<UserVideo> fetchVideo() {
List<UserVideo> list = [];
list.add(UserVideo(image: '', url: mockVideo, desc: 'Test1'));
list.add(UserVideo(image: '', url: mV2, desc: 'MV_TEST_2'));
list.add(UserVideo(image: '', url: mV3, desc: 'MV_TEST_3'));
list.add(UserVideo(image: '', url: mV4, desc: 'MV_TEST_4'));
return list;
}
I can use it like this and no error.
videoDataList = UserVideo.fetchVideo();
Your method getData() returns a Future:
Future<List<UserVideo>> getData() async {
List<UserVideo> list = [];
try {
var deviceid = '123';
var dtgUid = '100';
var nodata;
var bodyss = {
"uid": dtgUid,
"deviceid": deviceid,
};
You have to use async/await to call the method getData():
List<UserVideo> videoDataList = [];
videoDataList = await UserVideo.getData();
or use then():
List<UserVideo> videoDataList = [];
UserVideo.getData().then((list){
videoDataList = list;
});
Note: To use await you need to declare a method async