Yesitha
Yesitha

Reputation: 75

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";
    }
  }
}

Upvotes: 1

Views: 3883

Answers (3)

fredrick rogath
fredrick rogath

Reputation: 41

Worked for me after initializing variable to something or null, then waiting for initialization:
Example

 1. List _items = [];

2. this._items = await itemsDatabase.instance.readAllItems(); "inside initState"

when an app runs, _items have something empty initialized, after some time the real values are going to replace the null value.

Upvotes: 0

cameron1024
cameron1024

Reputation: 10206

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
}

Upvotes: 1

Y. Sampaio
Y. Sampaio

Reputation: 78

When adding "late" to a variable, you guarantee which variable will be initialized, so it makes no sense to compare it to null, because it can never be null. If you compare a variable with "late" without having initialized an exception occurs.

In your case, the best option is to use a bool variable to monitor progress.

class _ImageGridItemState extends State<ImageGridItem> {
  late Uint8List imageFile;
  bool isLoading = true;

  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!;
          isLoading = false;
        });
        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 (isLoading) {
      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";
    }
  }
}

Upvotes: 1

Related Questions