so Iam trying to build flutter maps with the nearest location and I gotten so far hear and the is an error 'inApplicationBloc()' especially in this segment segment
ApplicationBloc() {
setCurrentLocation();
}
and this is the erorr Non-nullable instance field 'currentLocation' must be initialized. Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late' once I add late initializer I get a red screen error I tryed adding ? to positon and null check in the latitude and longitude but it keeps giving me progress circle indicator and here is my code to get a better understanding
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import '../scr/screens/services/geolocatator_services.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class ApplicationBloc with ChangeNotifier {
final geolocatorService = GeolocatorService();
Position currentLocation; //must change late
ApplicationBloc() {
setCurrentLocation();
}
setCurrentLocation() async {
currentLocation = await geolocatorService.getCurrentLocation();
notifyListeners();
}
}
//second class
import 'package:geolocator/geolocator.dart';
class GeolocatorService {
Future<Position>setCurrentLocation() async {
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high);
}
getCurrentLocation() {}
}
Third class
import 'package:firebase/googlemaps_screens/blocks/app_block.dart';
import 'package:firebase/googlemaps_screens/blocks/app_block.dart';
import 'package:firebase/googlemaps_screens/mainrun.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:provider/provider.dart';
import '../../blocks/app_block.dart';
class HomeScreen extends StatefulWidget {
HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
void initState() {
Position currentLocation;
super.initState();
}
Widget build(BuildContext context) {
final applicationBloc = Provider.of<ApplicationBloc>(context);
return Scaffold(
body: (applicationBloc.currentLocation == null)
? Center(
child: CircularProgressIndicator(),
)
: ListView(
children: [
TextField(
decoration: InputDecoration(hintText: 'Search Location'),
),
Container(
height: 300.0,
child: GoogleMap(
mapType: MapType.normal,
myLocationEnabled: true,
initialCameraPosition: CameraPosition(
target: LatLng(
applicationBloc.currentLocation.latitude,
applicationBloc.currentLocation.longitude,
),
zoom: 14,
),
),
)
],
));
}
}
CodePudding user response:
currentLocation
still isn't initialized, in your initState()
what you called was the instance of currentLocation
which still wasn't initialized anywhere, except in your setCurrentLocation()
method, then you have to call the setCurrentLocation()
in initState, then you can mark currentLocation
as late
Alright so in flutter when you don't want to make a value nullable, because flutter needs to make sure no value is unnecessarily left null, you either have to mark it as a nullable value, orrr mark it as late, if you make it late, then you promise flutter you're going to initialize it later, now if you mark currentLocation
as late, it means you promise that you'll give it a value somewhere along the line, and it will never be null before the UI builds and from what I see, it can only get a value after your device gives access to the app to check user location, and then the app grabs it from the device GPS, if you have to do all that, meaning that through that process, the value of currentLocation
will be NULL,until it gets location and the builder won't have anything to build the UI with, also, in your HomeScreen build method, you are checking if the currentLocation is null, meaning you expect it to be null at some point, this is why it's advisable to make the currentLocation
nullable by adding a question mark, or mark it as late, which means it can't be null, but you promise that it'll get a value later, my advice would be to make it Position? currentLocation;
meaning that at some point it will be null....
so either make it
Position? currentLocation;
OR
late Position currentLocation;
but with second option you have to make sure that the app gets the location before the builder builds the UI, meaning you'll eliminate the circularprogressbar,
just do this
Position? currentLocation;
CodePudding user response:
Here so first main.dart pushes me to the loading_screen
i wrote this without Provider, just good ole state management
Geolocator Service
import 'package:geolocator/geolocator.dart';
class GeolocatorService {
Future<Position> setCurrentLocation() async {
await Geolocator.requestPermission();
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high);
}
}
here it requests permission of user to access location, then it gets location if user accepts,
Loading Screen
import 'package:flutter/material.dart';
import 'geolocator_service.dart';
import 'package:geolocator/geolocator.dart';
import 'home_screen.dart';
class LoadingScreen extends StatefulWidget {
const LoadingScreen({Key? key}) : super(key: key);
@override
State<LoadingScreen> createState() => _LoadingScreenState();
}
class _LoadingScreenState extends State<LoadingScreen> {
void getLocation() async {
Position position = await GeolocatorService().setCurrentLocation();
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => HomeScreen(
position: position,
),
),
);
}
@override
initState() {
super.initState();
getLocation();
}
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(child: CircularProgressIndicator()),
);
}
}
in the loading screen I have a method getLocation
which gets me the location by calling the setCurrentLocation()
method in the geolocator service class,then awaits the response, after it gets the response, it saves it in a position
variable, this is the same variable you had a problem initializing, now, here i put the whole thing in initState, so that position must get initialized once the app starts, then pushes me to the HomeScreen()
Home Screen
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key, required this.position}) : super(key: key);
final Position position;
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
const TextField(
decoration: InputDecoration(hintText: 'Search Location'),
),
Container(
height: 300.0,
child: GoogleMap(
mapType: MapType.normal,
myLocationEnabled: true,
initialCameraPosition: CameraPosition(
target: LatLng(
widget.position.latitude,
widget.position.longitude,
),
zoom: 14,
),
),
)
],
));
}
}
finally in HomeScreen, it takes the position that was pushed to this page after it was initialized in the loading screen, and then builds the UI with it
The problem you had was that you weren't calling any methods that initialized the position variable, all you did was create the method that gave it a value, so, the circular progress indicator kept rolling why? because the value was still null, you set the value in a method, but you didn't call the method, the method was just there, dormant, wasn't called anywhere, so until you call the method where you gave position
a value, then position
won't get a value, and it'll keep being null
IF YOU'RE STILL CONFUSED, ASK ME