【问题标题】:How to get Flutter Firebase Storage in a separate method?如何以单独的方法获取 Flutter Firebase 存储?
【发布时间】:2018-07-14 05:44:12
【问题描述】:

我已成功将图像保存到我的 Firebase 存储参考中。现在我需要下载它。我见过的例子都是用同样的方法上传和下载,用同样的StorageUploadTask和这行代码...

final Uri downloadUrl = (await uploadTask.future).downloadUrl;

我的问题是如何从不需要 uploadTask.future 的单独方法获取 downloadUrl,因为我只是在 FirebaseUser 更新他们的个人资料图片时上传图片?

【问题讨论】:

    标签: url firebase-storage flutter download


    【解决方案1】:

    StorageReference 现在有 Future<dynamic> getDownloadURL() 方法。将结果重新键入 String 并将其与您的 NetworkImage 小部件一起使用:

    import 'package:firebase_storage/firebase_storage.dart';
    import 'package:flutter/material.dart';
    import 'package:meta/meta.dart';
    
    class FirestoreImage extends StatefulWidget {
      final StorageReference reference;
      final Widget fallback;
      final ImageProvider placeholder;
    
      FirestoreImage(
          {Key key,
          @required this.reference,
          @required this.fallback,
          @required this.placeholder});
    
      @override
      FirestoreImageState createState() =>
          FirestoreImageState(reference, fallback, placeholder);
    }
    
    class FirestoreImageState extends State<FirestoreImage> {
      final Widget fallback;
      final ImageProvider placeholder;
    
      String _imageUrl;
      bool _loaded = false;
    
      _setImageData(dynamic url) {
        setState(() {
          _loaded = true;
          _imageUrl = url;
        });
      }
    
      _setError() {
        setState(() {
          _loaded = false;
        });
      }
    
      FirestoreImageState(
          StorageReference reference, this.fallback, this.placeholder) {
        reference.getDownloadURL().then(_setImageData).catchError((err) {
          _setError();
        });
      }
    
      @override
      Widget build(BuildContext context) => _loaded
          ? FadeInImage(
              image: NetworkImage(_imageUrl),
              placeholder: placeholder,
            )
          : fallback;
    }
    

    旧答案:

    我刚刚开始使用 Flutter (Dart) 进行开发,所以我的答案肯定不会完美(甚至可能很糟糕),但我是这样做的:

    import 'dart:typed_data';
    
    import 'package:firebase_storage/firebase_storage.dart';
    import 'package:flutter/material.dart';
    
    class FirestoreImage extends StatefulWidget {
    
      final StorageReference _reference;
    
      FirestoreImage(this._reference);
    
      @override
      FirestoreImageState createState() => FirestoreImageState(_reference);
    }
    
    class FirestoreImageState extends State<FirestoreImage> {
    
      Uint8List _imageData;
    
      _setImageData(Uint8List data) {
        setState(() {
          _imageData = data;
        });
      }
    
      FirestoreImageState(StorageReference reference) {
        reference
            .getData(0x3FFFFFFF)
            .then(_setImageData)
            .catchError((err) {});
      }
    
      @override
      Widget build(BuildContext context) =>
          _imageData == null ? Container() : Image.memory(_imageData);
    }
    

    现在您可以通过调用new FirestoreImage(imageStorageReference) 来显示FirestoreImage。也许通过扩展Image 有更好的方法

    【讨论】:

      【解决方案2】:

      VizGhar 提供了一个nice solution。 我已经清理了课程,添加了一些功能和文档。

      this gist 上也有。

      import 'package:firebase_storage/firebase_storage.dart';
      import 'package:flutter/material.dart';
      import 'package:meta/meta.dart';
      
      enum ImageDownloadState { Idle, GettingURL, Downloading, Done, Error }
      
      class FirebaseStorageImage extends StatefulWidget {
        /// The reference of the image that has to be loaded.
        final StorageReference reference;
        /// The widget that will be displayed when loading if no [placeholderImage] is set.
        final Widget fallbackWidget;
        /// The widget that will be displayed if an error occurs.
        final Widget errorWidget;
        /// The image that will be displayed when loading if no [fallbackWidget] is set.
        final ImageProvider placeholderImage;
      
        FirebaseStorageImage(
            {Key key,
            @required this.reference,
            @required this.errorWidget,
            this.fallbackWidget,
            this.placeholderImage}) {
          assert(
              (this.fallbackWidget == null && this.placeholderImage != null) ||
                  (this.fallbackWidget != null && this.placeholderImage == null),
              "Either [fallbackWidget] or [placeholderImage] must not be null.");
        }
      
        @override
        _FirebaseStorageImageState createState() => _FirebaseStorageImageState(
            reference, fallbackWidget, errorWidget, placeholderImage);
      }
      
      class _FirebaseStorageImageState extends State<FirebaseStorageImage>
          with SingleTickerProviderStateMixin {
        _FirebaseStorageImageState(StorageReference reference, this.fallbackWidget,
            this.errorWidget, this.placeholderImage) {
          var url = reference.getDownloadURL();
          this._imageDownloadState = ImageDownloadState.GettingURL;
          url.then(this._setImageData).catchError((err) {
            this._setError();
          });
        }
      
        /// The widget that will be displayed when loading if no [placeholderImage] is set.
        final Widget fallbackWidget;
        /// The widget that will be displayed if an error occurs.
        final Widget errorWidget;
        /// The image that will be displayed when loading if no [fallbackWidget] is set.
        final ImageProvider placeholderImage;
      
        /// The image that will be/has been downloaded from the [reference].
        Image _networkImage;
        /// The state of the [_networkImage].
        ImageDownloadState _imageDownloadState = ImageDownloadState.Idle;
      
        /// Sets the [_networkImage] to the image downloaded from [url].
        void _setImageData(dynamic url) {
          this._networkImage = Image.network(url);
          this
              ._networkImage
              .image
              .resolve(ImageConfiguration())
              .addListener((_, __) {
            if (mounted)
              setState(() => this._imageDownloadState = ImageDownloadState.Done);
          });
          if (this._imageDownloadState != ImageDownloadState.Done)
            this._imageDownloadState = ImageDownloadState.Downloading;
        }
      
        /// Sets the [_imageDownloadState] to [ImageDownloadState.Error] and redraws the UI.
        void _setError() {
          if (mounted)
            setState(() => this._imageDownloadState = ImageDownloadState.Error);
        }
      
        @override
        Widget build(BuildContext context) {
          switch (this._imageDownloadState) {
            case ImageDownloadState.Idle:
            case ImageDownloadState.GettingURL:
            case ImageDownloadState.Downloading:
              return Image(image: this.placeholderImage) ?? this.fallbackWidget;
            case ImageDownloadState.Error:
              return this.errorWidget;
            case ImageDownloadState.Done:
              return this._networkImage;
              break;
            default:
              return this.errorWidget;
          }
        }
      }
      

      【讨论】:

      • 很高兴有人完成了它:)
      【解决方案3】:

      不可能(还)。您需要自己将该 uri 存储在数据库中。

      但您可以并且应该使用 getData 而不是在 Firebase 应用中使用下载网址。

      【讨论】:

      • 感谢您的澄清。 getData() 在参数中要求 Future。这是为了压缩吗?推荐的尺寸是多少?
      • Uint8List 只是文件的内容(以字节为单位)。至于 maxSize 参数,你可以放一个你知道你的文件不会超过的任意大小。
      • 如果你想要可缓存的东西,这是一个糟糕的解决方案
      • getDownloadURL 在回答时不存在
      猜你喜欢
      • 2020-03-28
      • 2020-04-23
      • 2023-03-03
      • 2021-08-20
      • 1970-01-01
      • 2018-07-04
      • 2020-03-26
      • 2020-07-15
      • 2020-09-23
      相关资源
      最近更新 更多