Search code examples
androidflutterfirebaseopenweathermapweather-api

LateInitialization error: Field 'city' not initialized. Getting a white screen after user reopens the app after logging in using SharedPreferences


I have built a Weather App that fetches data using OpenWeather API. I have also used SharedPreferences to remember the user next time he opens the app. But, on reopening the app...it shows the LateInitialization error: Field 'city' has not initialised. Can anyone help me out it with?

main.dart code:

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:untitled/Screens/mainScreen.dart';
import 'package:untitled/Screens/loginscreen.dart';
import 'Network/Location.dart';
import '../constants.dart' as Constants;
import 'firebase_options.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final prefs = await SharedPreferences.getInstance();
  final isLoggedIn = prefs.getBool('isLoggedIn') ?? false;

  await Firebase.initializeApp(
      options: DefaultFirebaseOptions.currentPlatform );

  apiCall();

  runApp(MyApp(isLoggedIn: isLoggedIn));

}

int myvar=1;

Future<void> apiCall() async {
  var location = await determinePosition();

  myvar = await Constants.apiInstance.getLocation(
      location.latitude.toString(), location.longitude.toString());
  print(location.latitude.toString());
}
class MyApp extends StatelessWidget {
  final bool isLoggedIn;
  const MyApp( {super.key, required this.isLoggedIn});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {   //build context helps to identify controller to build widgets
    return MaterialApp(               // MaterialApp widget is the main screen of the app
      debugShowCheckedModeBanner: false,
        home: isLoggedIn ? const MainScreen() : const LoginScreen()

    );
  }
}

LoginScreen.dart code where api() is called:

class MainScreen extends StatefulWidget {
  const MainScreen({Key? key}) : super(key: key);
  
  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {

  int myvar=1;
  @override

  void initState() {
    // TODO: implement initState
    apiCall();
    super.initState();

  }
  void apiCall() async {
    var location = await determinePosition();

    myvar = await Constants.apiInstance.getLocation(
        location.latitude.toString(), location.longitude.toString());
    print(location.latitude.toString());
  }

MainScreen.dart is the screen that shows weather data:

  class _MainScreenState extends State<MainScreen> {
  @override
  Widget build(BuildContext context) {
  Size size = MediaQuery.of(context).size;
    return Container(
    decoration: BoxDecoration(
      image: DecorationImage(
    image: NetworkImage(
        'https://images.unsplash.com/photo-1516912481808-3406841bd33c?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8M3x8d2VhdGhlcnxlbnwwfHwwfHw%3D&w=1000&q=80'),
    fit: BoxFit.cover,
  )),
  child: Stack(
    alignment: Alignment.center,
    children: [
      Positioned(
        top: size.height * 0.1,
        child: Row(
          children: <Widget>[
            Text(
              '${Constants.apiInstance.city},',
              style: TextStyle(
                decoration: TextDecoration.none,
                color: Colors.cyanAccent,
                fontSize: 45,
              ),
            ),

Tried to change the position of apiCall() but nothing worked out for me.


Solution

  • So i have got answered this questions from one of my seniors.

    So the solution is to add the await keyword before the apiCall() function in main.dart file.

    This is so because, my apiCall() function is an asynchronous function and that marks that the function supports await.

    • Asynchronous function returns the type of future.
    • We put await keyword in front of async function to make the subsequence lines of code waiting for that future's result.