Search code examples
androidfirebaseflutterdartruntime-error

Late Initialization error appears till images loading from firebase


I am working on an app that fetches images from Firebase Storage to the list view Widget. Images were load from Firebase with no issue but there is an error that appears till loading the images from firebase called " LateInitializationError: Field 'imageFile' has not been initialized.".Is there is any solution for this?

class GuidePage extends StatefulWidget {
  @override
  _GuidePageState createState() => _GuidePageState();
}

class _GuidePageState extends State<GuidePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          width: MediaQuery.of(context).size.width,
          height: MediaQuery.of(context).size.height,
          decoration: BoxDecoration(
            image: DecorationImage(
              image: AssetImage("images/b.png"),
              fit: BoxFit.fill,
            ),
          ),
          child: SafeArea(
            child: InteractiveViewer(
              child: Container(
                  margin: EdgeInsets.symmetric(vertical: 20.0),
                  child: ListView.builder(
                      itemCount: getIndex(),
                      itemBuilder: (context, index) {
                        return ImageGridItem(index + 1); //image return
                      })),
            ),
          ),
        ),
      ),
    );
  }

  getIndex() {
    if (isEnglish) {
      return 208;
    } else {
      return 259;
    }
  }
}

class ImageGridItem extends StatefulWidget {
  int index = 1;

  ImageGridItem(int i) {
    this.index = i;
  }

  @override
  _ImageGridItemState createState() => _ImageGridItemState();
}

class _ImageGridItemState extends State<ImageGridItem> {
  late Uint8List imageFile;

  Reference photosReference =
      FirebaseStorage.instance.ref().child(getNameChild1());

  getImage() {
    if (!imageData.containsKey(widget.index)) {
      photosReference
          .child(getNameChild2())
          .getData(2 * 1024 * 1024)
          .then((data) {
        this.setState(() {
          imageFile = data!;
        });
        imageData.putIfAbsent(widget.index, () {
          requestedIndexes.add(widget.index);
          

          return imageFile;
        });
      }).catchError((error) {
        print(error);
      });
    } else {
      imageFile = imageData[widget.index]!;
    }
  }

  @override
  void initState() {
    super.initState();
    if (!imageData.containsKey(widget.index)) {
      getImage();
    } else {
      this.setState(() {
        imageFile = imageData[widget.index]!;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    if (imageFile == null) {
      CircularProgressIndicator();
      return Text("Empty");
    } else {
      return Image.memory(
        imageFile,
        fit: BoxFit.cover,
      );
    }
  }

  String CreateFinalIndex(int index) {
    int index_length = widget.index.toString().length;
    String zero_number = "0" * ((3 - index_length));
    String Final_Index = (zero_number + widget.index.toString());
    return Final_Index;
  }

  
  static getNameChild1() {
    if (isEnglish) {
      return "Guide";
    } else {
      return "GuideS";
    }
  }

  String getNameChild2() {
    String Final_Index = CreateFinalIndex(widget.index);
    if (isEnglish) {
      return "eGr12TG ICT-$Final_Index.jpg";
    } else {
      return "sGr12TG ICT-$Final_Index.jpg";
    }
  }
}


Solution

  • In Dart, all non-late variables are initialized to null. If a variable is non-nullable, it would be an error if this ever contained null, so this is a compile time error:

    int? myInt;  // initialized to null
    String myString;  // compile-time error
    

    But late is slightly different. Instead of being initialized to null, a late field is not initialized. This means that the first time you try to get that variable, it must have been manually initialized, otherwise you get a LateInitializationError.

    In short, you cannot use != null to test whether a late variable has been intialized.

    Some solutions:

    1. Make your field nullable
    Uint8List? data;
    
    @override
    Widget build(BuildContext context) {
      if (data == null) return LoadingWidget();
      final nonNullData = data!;
      // now use the data to return the image
    }
    
    1. Store an extra boolean that represents "whether the variable is initialized":
    late Uint8List data;
    var isInitialized = false;
    
    Future<void> loadData() async {
      data = await getImageFromNetwork();
      isInitialized = true;
    }
    
    @override
    Widget build(BuildContext context) {
      if (!isInitialized) return LoadingWidget();
      // now use the data to return the image
    }