Home > Blockchain >  what is initializer error and how to fix it in flutte
what is initializer error and how to fix it in flutte

Time:05-08

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

  • Related