Flutter 颤振:除非热重新加载,否则加载资源错误(块和多图像选择器)

Flutter 颤振:除非热重新加载,否则加载资源错误(块和多图像选择器),flutter,Flutter,我遇到了一个奇怪的问题,加载从MultiImagePicker转换的文件仅在热重新加载页面后才能成功加载,否则返回以下错误: 未处理的异常:无法加载资产:/storage/simulated/0/DCIM/Camera/IMG_20191105_104542.jpg 步骤: @override void initState() { super.initState(); setState(() { _galleryBloc.getGalleryImages( docRef: Fi

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

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

步骤:

 @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);
  }
 // -----------------------------------------------------------------------------
// Convert File to Asset
// -----------------------------------------------------------------------------
  Future<File> _convertAssetToFile(String path) async {

    final file = File(path);

    return file;
  }
  • initState从Firestore加载现有图像字符串,这些字符串通过DefaultCacheManager缓存到文件中,并添加到tmpGalleryImages列表中

  • 添加图像使用MultiImagePicker,然后将其从资源转换为文件并添加到TMPGalleryImage列表中

  • 我创建了一个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);
    });
    
    @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);
      }
    
     // -----------------------------------------------------------------------------
    // Convert File to Asset
    // -----------------------------------------------------------------------------
      Future<File> _convertAssetToFile(String path) async {
    
        final file = File(path);
    
        return file;
      }
    
    }

    StreamBuilder:

     @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);
      }
    
     // -----------------------------------------------------------------------------
    // Convert File to Asset
    // -----------------------------------------------------------------------------
      Future<File> _convertAssetToFile(String path) async {
    
        final file = File(path);
    
        return file;
      }
    
    @覆盖
    小部件构建(构建上下文){
    返回流生成器(
    流:_galleryBloc.multipleImageStream,
    生成器:(上下文,快照){
    if(snapshot.connectionState==connectionState.none){
    打印(“无”);
    }
    if(snapshot.connectionState==connectionState.waiting){
    打印(“等待”);
    }
    返回列(
    儿童:[
    GridView.builder(
    gridDelegate:SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:4),
    itemCount:snapshot.data.length\u ShowGallerySpeoptions(
    上下文:上下文,
    tmpgalleryImage:snapshot.data,
    imageLimit:widget.imageLimit,
    文件名:“img_${index+1}”,
    ),
    孩子:卡片(
    儿童:中心(
    子:图标(Icons.add),
    ),
    ),
    )
    :后台();
    },
    ),
    
    集团:

     @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);
      }
    
     // -----------------------------------------------------------------------------
    // Convert File to Asset
    // -----------------------------------------------------------------------------
      Future<File> _convertAssetToFile(String path) async {
    
        final file = File(path);
    
        return file;
      }
    
    class GalleryBloc{
    final _multipleImageController=StreamController.broadcast();
    Stream get multipleImageStream=>\u multipleImageController.Stream;
    // -----------------------------------------------------------------------------
    //加载现有库图像
    // -----------------------------------------------------------------------------
    未来的GetGalleryImage({DocumentReference docRef,List TMPGalleryImage,函数回调})异步{
    试一试{
    等待docRef.get(),然后(
    (值)异步{
    if(value.data!=null&&tmpGalleryImages.length==0){
    for(var img在value.data['gallery_images']中){
    File fetchedFile=await DefaultCacheManager().getSingleFile(img);
    tmpgallerymages.add(fetchedFile);
    }
    }
    },
    );
    }捕获(e){
    打印(如toString());
    }
    回调(TMPGalleryImage);
    _multipleImageController.sink.add(tmpgalleryImage);
    }
    // -----------------------------------------------------------------------------
    //将文件转换为资产
    // -----------------------------------------------------------------------------
    Future\u convertAssetToFile(字符串路径)异步{
    final byteData=wait rootBundle.load(路径);
    最终文件=文件(路径);
    wait file.writeAsBytes(byteData.buffer.asUint8List(byteData.offsetInBytes,byteData.lengthInBytes));
    返回文件;
    }
    // -----------------------------------------------------------------------------
    //选择多个图像
    // -----------------------------------------------------------------------------
    未来的pickMultipleImages({List tmpGalleryImages,int-imageLimit,Function callback})异步{
    试一试{
    等待MultiImagePicker.pickImages(
    最大值:imageLimit-tmpGalleryImages.length,
    ).then((chosenImages)异步{
    for(chosenImages中的变量路径){
    wait_convertAssetToFile(wait path.filePath)。然后(
    (转换文件){
    tmpgallerymages.add(convertedFile);
    },
    );
    }
    });
    }关于异常捕获(e){
    打印(如toString());
    }
    _multipleImageController.sink.add(tmpgalleryImage);
    回调(TMPGalleryImage);
    }
    
    如果有人能为我的错误提供一些指导,我将不胜感激

    根据IGOR的答案更新代码(有效):

     @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);
      }
    
     // -----------------------------------------------------------------------------
    // Convert File to Asset
    // -----------------------------------------------------------------------------
      Future<File> _convertAssetToFile(String path) async {
    
        final file = File(path);
    
        return file;
      }
    
    //-----------------------------------------------------------------------------
    //将文件转换为资产
    // -----------------------------------------------------------------------------
    Future\u convertAssetToFile(字符串路径)异步{
    最终文件=文件(路径);
    返回文件;
    }
    
    不要使用rootBundle通过pubspec.yaml打开应用程序未打包的文件。请使用File类打开它们

    rootBundle包含与打包在一起的资源 应用程序生成时。将资源添加到rootB