繁体   English   中英

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

[英]Flutter: Loading asset error unless hot reload (BLOC + MultiImagePicker)

我有一个奇怪的问题,加载从 MultiImagePicker 转换的文件只有在热重新加载页面后才能成功加载,否则返回以下错误:

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

脚步:

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

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

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

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

初始化状态:

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

}

流生成器:

@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();
              },
            ),

集团:

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

不要使用rootBundle打开未通过 pubspec.yaml 与应用打包的文件。 使用文件 class 打开它们。

rootBundle 包含在构建应用程序时与应用程序一起打包的资源。 要将资源添加到应用程序的 rootBundle,请将它们添加到应用程序 pubspec.yaml 清单的 flutter 部分的 assets 子部分。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM