I am trying to get all the cars from my backend when I land on the car_map screen but I get the following exception.
I use Futures to get the list of the cars.
======== Exception caught by widgets library =======================================================
The following NoSuchMethodError was thrown building FutureBuilder<List<Object>>(dirty, dependencies: [MediaQuery], state: _FutureBuilderState<List<Object>>#33dda):
The method 'forEach' was called on null.
Receiver: null
Tried calling: forEach(Closure: (CarModel) => Null)
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:63:5)
#1 _CarMapState._carsMapView (package:Caroo/screens/car_map/car_map.dart:121:13)
#2 _CarMapState._carsMapWidget.<anonymous closure> (package:Caroo/screens/car_map/car_map.dart:242:22)
#3 _FutureBuilderState.build (package:flutter/src/widgets/async.dart:782:55)
#4 StatefulElement.build (package:flutter/src/widgets/framework.dart:4782:27)
#5 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4665:15)
#6 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4840:11)
#7 Element.rebuild (package:flutter/src/widgets/framework.dart:4355:5)
import 'package:flutter/material.dart';
import 'package:latlong2/latlong.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:geolocator/geolocator.dart';
import 'package:Caroo/bloc.navigation_bloc/navigation_bloc.dart';
import 'package:Caroo/style.dart';
import 'package:Caroo/api.dart';
import 'package:Caroo/models/car.dart';
import 'package:Caroo/screens/car_map/car_map_item.dart';
class CarMap extends StatefulWidget with NavigationStates {
CarMap({this.onPush, this.userID});
final String userID;
final Function onPush;
@override
_CarMapState createState() => new _CarMapState();
}
class _CarMapState extends State<CarMap> {
final Api api = Api();
Future<List<CarModel>> _cars;
Future<List<bool>> _userState;
Future<Position> _currPosition;
int _selectedCar = -1;
MapController controller = MapController();
Future<List<CarModel>> _getCars() async {
return await api.getCarList().catchError((e) {
if (e.toString() == 'NO_AUTH') {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Error in cars list'),
duration: Duration(seconds: 5),
backgroundColor: Colors.red));
throw Exception('error');
}
});
}
Future<List<bool>> _getUserState() async {
return await api.userState().catchError((e) {
if (e.toString() == 'NO_AUTH') {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Error in user state'),
duration: Duration(seconds: 5),
backgroundColor: Colors.red));
throw Exception('Error in user state');
}
});
}
Future<Position> _getCurrPosition() async {
Future<Position> result =
Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.best);
return result;
}
// void filterCars() async {
// var filtering = await widget.onPush(context, widget, '/map_filter', null);
// setState(() {});
// }
@override
void initState() {
super.initState();
_userState = _getUserState();
_cars = _getCars();
_currPosition = _getCurrPosition();
}
// @override
// void dispose() {
// super.dispose();
//
// }
void _onCarTapped(CarModel car, bool isAuthorized) {
if (car.isAvailable) {
showModalBottomSheet<void>(
context: context,
backgroundColor: Colors.transparent,
builder: (BuildContext context) {
return CarMapItem(
car: car,
onPush: widget.onPush,
isAuthorized: isAuthorized,
);
});
}
debugPrint('Marker tapped ' + _selectedCar.toString());
}
Widget _carsMapView(BuildContext context, AsyncSnapshot snapshot) {
Size size = MediaQuery.of(context).size;
// final List<CarModel> carList = snapshot.data;
// final bool isAuthorized = true;
// final bool isRejected = true;
final List<CarModel> carList = snapshot.data[0];
debugPrint(snapshot.data[0]);
final bool isAuthorized = snapshot.data[1][0];
final bool isRejected = snapshot.data[1][1];
final Position _currPosition = snapshot.data[2];
List<Marker> markers = [
new Marker(
width: 45.0,
height: 45.0,
point: LatLng(_currPosition.latitude, _currPosition.longitude),
builder: (context) => new Container(
child: IconButton(
icon: Icon(Icons.location_on),
color: Colors.red,
iconSize: 45.0,
onPressed: () => {},
),
),
),
];
carList.forEach((car) {
markers.add(
new Marker(
width: 45.0,
height: 45.0,
point: new LatLng(car.latitude, car.longitude),
builder: (context) => new Container(
child: IconButton(
icon: Icon(Icons.location_on),
color: car.isAvailable ? PrimaryColor : Colors.grey[500],
iconSize: 45.0,
onPressed: () => _onCarTapped(car, isAuthorized),
),
),
),
);
});
return new Scaffold(
floatingActionButton: Padding(
padding: EdgeInsets.only(bottom: 60),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
//!! FILTER CARS !!
// Container(
// width: 35,
// child: FloatingActionButton(
// heroTag: "Filter",
// tooltip: 'Cars filter',
// onPressed: () => filterCars(),
// child: Icon(Icons.filter_alt, size: 18, color: PrimaryColor,),
// backgroundColor: Colors.white,
// ),
// ),
// SizedBox(height: size.height*0.01),
Container(
width: 50,
child: FloatingActionButton(
heroTag: "Recenter",
tooltip: 'Recenter',
onPressed: () {
setState(() {
_getCurrPosition();
});
// TODO: Change move controller.
controller.onReady;
controller.move(
new LatLng(
_currPosition.latitude, _currPosition.longitude),
controller.zoom);
},
child: Icon(
Icons.gps_fixed,
size: 25,
color: PrimaryColor,
),
backgroundColor: Colors.white,
),
),
],
),
),
body: Container(
// height: size.height,
child: Stack(
children: [
FlutterMap(
// mapController: controller,
options: MapOptions(
center: LatLng(_currPosition.latitude, _currPosition.longitude),
minZoom: 15.0,
),
layers: [
new TileLayerOptions(
// urlTemplate: "https://api.mapbox.com/styles/v1/dbalaskas/ckf8bizf717go19mkvp48ifvf/tiles/256/{z}/{x}/{y}@2x?access_token=pk.eyJ1IjoiZGJhbGFza2FzIiwiYSI6ImNrZjg5NG41OTBhMDYycm1hM3RzYWVpbXoifQ.jjsmEKanqLYld1dXfkLPRQ",
urlTemplate:
"https://api.mapbox.com/styles/v1/dbalaskas/ckg7znggm231g19qowxpz2xq5/tiles/256/{z}/{x}/{y}@2x?access_token=pk.eyJ1IjoiZGJhbGFza2FzIiwiYSI6ImNrZjg5NG41OTBhMDYycm1hM3RzYWVpbXoifQ.jjsmEKanqLYld1dXfkLPRQ",
additionalOptions: {
// 'accessToken': 'pk.eyJ1IjoiZGJhbGFza2FzIiwiYSI6ImNrZjg5NG41OTBhMDYycm1hM3RzYWVpbXoifQ.jjsmEKanqLYld1dXfkLPRQ',
// 'id': 'mapbox.mapbox-streets-v8'
'accessToken':
'pk.eyJ1IjoiZGJhbGFza2FzIiwiYSI6ImNrZjg5NG41OTBhMDYycm1hM3RzYWVpbXoifQ.jjsmEKanqLYld1dXfkLPRQ',
'id': 'mapbox://styles/dbalaskas/ckg7znggm231g19qowxpz2xq5'
},
),
new MarkerLayerOptions(
markers: markers,
)
],
),
if (!isAuthorized && !isRejected)
Positioned(
left: size.width * 0.025,
top: size.height * 0.05,
child: _notAuthorized(context),
),
if (isRejected)
Positioned(
left: size.width * 0.025,
top: size.height * 0.05,
child: _notAcceptedLicense(context),
)
],
),
),
);
}
Widget _carsMapWidget() {
return FutureBuilder(
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
break;
case ConnectionState.done:
if (snapshot.hasError) {
debugPrint("ERROR_CAR_MAP >> ${snapshot.hasError}");
return widget.onPush(context, widget, '/logout', null);
} else if (snapshot.hasData) {
return _carsMapView(context, snapshot);
} else {
return Center(
child: Text("No data"),
);
}
break;
default:
if (snapshot.hasError) {
debugPrint("ERROR_CAR_MAP >> ${snapshot.hasError}");
return widget.onPush(context, widget, '/logout', null);
} else {
return _carsMapView(context, snapshot);
}
}
},
future: Future.wait([_cars, _userState, _currPosition]),
// future: _cars,
);
}
@override
Widget build(BuildContext context) {
// _userState = _getUserState();
// _cars = _getCars();
// _currPosition = _getCurrPosition();
return Scaffold(
body: WillPopScope(
onWillPop: () async {
return Future.value(true);
},
child: _carsMapWidget(),
),
);
}
}
Widget _notAuthorized(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Container(
// height: size.height*0.1,
width: size.width * 0.95,
margin: EdgeInsets.symmetric(vertical: 10),
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: NotAuthorizedBoxColor,
border: Border.all(color: Colors.black38, width: 1.3),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
child: Wrap(
alignment: WrapAlignment.center,
children: [
Text(
'Please wait for our team to authenticate your license.',
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 18),
textAlign: TextAlign.center,
),
Text(
'Thank you!',
style: TextStyle(fontSize: 18),
)
],
),
);
}
Widget _notAcceptedLicense(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Container(
width: size.width * 0.95,
margin: EdgeInsets.symmetric(vertical: 10),
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: NotAcceptedBoxColor,
border: Border.all(color: Colors.black38, width: 1.3),
borderRadius: BorderRadius.all(Radius.circular(20)),
),
child: Column(
children: [
Text(
'Please insert again pictures of your license to continue.',
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 18),
textAlign: TextAlign.center,
),
Text(
'Thank you!',
style: TextStyle(fontSize: 18),
)
],
),
);
}
My API call:
Future<List<CarModel>> getCarList() async {
String token = await storage.getToken();
debugPrint('(CARs) TOKEN: ' + token);
/*final response =
await http.get(Uri.encodeFull(_api_url + '/api/v1/cars/'), headers: {
'Accept': 'application/json; charset=utf-8',
HttpHeaders.authorizationHeader: 'Token $token'
});*/
final response =
await http.get(Uri.parse(_api_url + '/api/v1/cars/'), headers: {
'Accept': 'application/json; charset=utf-8',
HttpHeaders.authorizationHeader: 'Token $token'
});
debugPrint('getCarList response: ${response.body.toString()}');
if (response.statusCode == 200) {
return json
.decode(utf8.decode(response.bodyBytes))['result']
.map<CarModel>((item) {
try {
return CarModel.fromMappedJson(item);
} catch (e) {
return CarModel.fromMappedJson(item);
}
}).toList();
} else if (response.statusCode == 401) {
throw "get_car_list NO_AUTH";
} else {
throw "get_car_list ERROR";
}
}
getCarList response:
{
"result": [
{
"id": 1,
"car_brand": "SCONDA",
"car_model": "OCTAVIA",
"car_picture": "photos/cars/2021/11/14/%{self.brand}/%{self.model}/261-2616422_skoda-octavia-png-skoda-s_JfP1yEL.png",
"car_seatsNum": 5,
"city": "Athens",
"owner": "ARAMS.IKE",
"manufacturingDate": "2012",
"plate": "ZAZ 2120",
"price": "6.000",
"longitude": "23.769970",
"latitude": "37.977850",
"is_available": true,
"hasBluetooth": true,
"hasChildSeat": false,
"isPetFriendly": false
},
{
"id": 2,
"car_brand": "HUYNDAI",
"car_model": "i20",
"car_picture": "photos/cars/2021/11/14/%{self.brand}/%{self.model}/huyndai_i20.png",
"car_seatsNum": 5,
"city": "Athens",
"owner": "ARAMS.IKE",
"manufacturingDate": "2018",
"plate": "ΡÎÎ1234",
"price": "6.000",
"longitude": "23.758440",
"latitude": "37.977460",
"is_available": true,
"hasBluetooth": true,
"hasChildSeat": true,
"isPetFriendly": false
}
]
}