Flutter:除非热重加载,否则加载资产错误(BLOC + MultiImagePicker)

时间:2019-11-07 10:06:15

标签: flutter

我遇到了一个奇怪的问题,其中加载从MultiImagePicker转换的文件仅在热重新加载页面后才成功加载,否则它将返回以下错误:

  

未处理的异常:无法加载资产:/storage/emulated/0/DCIM/Camera/IMG_20191105_104542.jpg

步骤:

  1. initState从Firestore加载现有的图像字符串,这些字符串通过DefaultCacheManager缓存到File,并添加到tmpGalleryImages列表中。

  2. 添加图像使用MultiImagePicker,然后将其从Asset转换为File并添加到tmpGalleryImages列表。

  3. 我创建了一个SetState按钮来测试重新加载状态,但是在调用SetState之后仍然出现上述错误-所以我非常困惑为什么它只有在热重新加载后才能正常工作?

注意:通过转换为文件的麻烦,我可以将本地图像(资产)和Firestore图像(字符串)组合到一个列表中,可以对其进行编辑并重新上传到Firestore < / p>

initState:

 @override
void initState() {
super.initState();
setState(() {
  _galleryBloc.getGalleryImages(
      docRef: Firestore.instance.collection("galleries").document("gal_${widget.docId}"),
      tmpGalleryImages: widget.tmpGalleryImages,
      callback: widget.callback);
});

}

StreamBuilder:

@override
Widget build(BuildContext context) {
return StreamBuilder<List<File>>(
  stream: _galleryBloc.multipleImageStream,
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.none) {
      print("none");
    }
    if (snapshot.connectionState == ConnectionState.waiting) {
      print("Waiting");
    }

    return Column(
      children: <Widget>[
        GridView.builder(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 4),
          itemCount: snapshot.data.length < widget.imageLimit ? snapshot.data.length + 1 : snapshot.data.length,
          itemBuilder: (context, index) {
            return index < snapshot.data.length
                ? GalleryStepperThumbnail(
                    file: snapshot.data[index],
                    onTap: () {
                      _showGalleryStepperOptions(
                        context: context,
                        tmpGalleryImages: snapshot.data,
                        imageLimit: widget.imageLimit,
                        file: snapshot.data[index],
                        fileName: "img_${index + 1}",
                      );
                    })
                : snapshot.data.length < widget.imageLimit
                    ? InkWell(
                        onTap: () => _showGalleryStepperOptions(
                          context: context,
                          tmpGalleryImages: snapshot.data,
                          imageLimit: widget.imageLimit,
                          fileName: "img_${index + 1}",
                        ),
                        child: Card(
                          child: Center(
                            child: Icon(Icons.add),
                          ),
                        ),
                      )
                    : Offstage();
              },
            ),

BLOC:

class GalleryBloc {
  final _multipleImageController = StreamController<List<File>>.broadcast();
  Stream<List<File>> get multipleImageStream => _multipleImageController.stream;

// -----------------------------------------------------------------------------
// Load existing gallery images
// -----------------------------------------------------------------------------
  Future<void> getGalleryImages({DocumentReference docRef, List<File> tmpGalleryImages, Function callback}) async {
    try {
      await docRef.get().then(
        (value) async {
          if (value.data != null && tmpGalleryImages.length == 0) {
            for (var img in value.data['gallery_images']) {
              File fetchedFile = await DefaultCacheManager().getSingleFile(img);
          tmpGalleryImages.add(fetchedFile);
            }
          }
        },
       );
    } catch (e) {
      print(e.toString());
    }
    callback(tmpGalleryImages);
    _multipleImageController.sink.add(tmpGalleryImages);
   }


// -----------------------------------------------------------------------------
// Convert File to Asset
// -----------------------------------------------------------------------------
  Future<File> _convertAssetToFile(String path) async {
    final byteData = await rootBundle.load(path);

    final file = File(path);
    await file.writeAsBytes(byteData.buffer.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
    return file;
  }

// -----------------------------------------------------------------------------
// Select Multiple Images
// -----------------------------------------------------------------------------
  Future<void> pickMultipleImages({List<File> tmpGalleryImages, int imageLimit, Function callback}) async {

    try {
      await MultiImagePicker.pickImages(
        maxImages: imageLimit - tmpGalleryImages.length,
  ).then((chosenImages) async {
        for (var path in chosenImages) {
         await _convertAssetToFile(await path.filePath).then(
        (convertedFile) {
              tmpGalleryImages.add(convertedFile);
             },
          );
        }
      });
    } on Exception catch (e) {
      print(e.toString());
    }

    _multipleImageController.sink.add(tmpGalleryImages);
    callback(tmpGalleryImages);
  }

如果任何人都可以提供有关我要去哪里的指南,我将非常感谢!

基于IGOR的答案的更新代码(工作):

 // -----------------------------------------------------------------------------
// Convert File to Asset
// -----------------------------------------------------------------------------
  Future<File> _convertAssetToFile(String path) async {

    final file = File(path);

    return file;
  }

1 个答案:

答案 0 :(得分:1)

请勿使用 rootBundle 打开未通过pubspec.yaml与应用程序打包在一起的文件。用File类打开它们。

  

rootBundle包含与   构建时的应用程序。要将资源添加到rootBundle中   您的应用程序,将它们添加到flutter的Assets小节中   应用程序的pubspec.yaml清单的一部分。