在从 firebase 加载图像之前出现延迟初始化错误

Late Initialization error appears till images loading from firebase

我正在开发一个从 Firebase 存储中获取图像到列表视图小部件的应用程序。图片是从 Firebase 加载的,没有问题,但是在从 firebase 加载图片之前出现错误,称为“LateInitializationError:字段 'imageFile' 尚未初始化。”。对此有任何解决方案吗?

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

将“late”添加到变量时,您保证将初始化哪个变量,因此将它与 null 进行比较是没有意义的,因为它永远不可能为 null。如果在没有初始化的情况下将变量与“晚”进行比较,则会发生异常。

对于您的情况,最好的选择是使用 bool 变量来监控进度。

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

在 Dart 中,所有非 late 的变量都被初始化为 null。如果一个变量是不可为空的,那么如果它曾经包含 null 就会出错,所以这是一个编译时错误:

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

late 略有不同。 late 字段没有初始化为 null,而是 未初始化 。这意味着您第一次尝试获取该变量时,它 必须 已被手动初始化,否则您将得到一个 LateInitializationError.

简而言之,您不能使用!= null来测试一个late变量是否已经被初始化。

一些解决方案:

  1. 使您的字段可为空
Uint8List? data;

@override
Widget build(BuildContext context) {
  if (data == null) return LoadingWidget();
  final nonNullData = data!;
  // now use the data to return the image
}
  1. 存储一个额外的布尔值,表示“变量是否已初始化”:
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
}

在将变量初始化为某物或 null 后为我工作,然后等待初始化:
例子

 1. List _items = [];

2. this._items = await itemsDatabase.instance.readAllItems(); “在 initState 中”

当应用程序运行时,_items 会初始化一些空值,一段时间后实际值将替换空值。