如何以单独的方法获取 Flutter Firebase 存储?

Posted

技术标签:

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

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

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

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

【问题讨论】:

【参考方案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 在回答时不存在

以上是关于如何以单独的方法获取 Flutter Firebase 存储?的主要内容,如果未能解决你的问题,请参考以下文章