如何以单独的方法获取 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 存储?的主要内容,如果未能解决你的问题,请参考以下文章

Flutter,内部流构建器,如何根据未来获取流?

如何从我的简单.dart文件创建插件以在Flutter中使用?

如何在 Flutter 中从 Firebase Auth 获取用户 ID?

如何从 Flutter 中的 Jitsi Meet Conference 获取视频帧

Flutter从谷歌地图获取坐标

Flutter 如何优化 Firestore 存储读取以防止大量不必要的读取