【问题标题】:Flutter: Loading asset error unless hot reload (BLOC + MultiImagePicker)Flutter:加载资产错误,除非热重载(BLOC + MultiImagePicker)
【发布时间】:2020-03-03 21:24:20
【问题描述】:

我有一个奇怪的问题,加载从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 的列表中

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

集团:

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

【问题讨论】:

    标签: flutter


    【解决方案1】:

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

    rootBundle 包含与 构建时的应用程序。为 rootBundle 添加资源 您的应用程序,将它们添加到颤振的资产子部分 应用程序 pubspec.yaml 清单的部分。

    【讨论】:

    • 我有完全不必要的步骤 - 非常感谢您指出这一点!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-15
    • 2021-06-21
    • 2020-04-28
    • 2021-05-10
    • 2020-04-11
    • 1970-01-01
    • 2012-02-21
    相关资源
    最近更新 更多