首页 > 解决方案 > 如何将图像上传到 Firebase Storage 并自动存储在 Cloud Firestore 中?

问题描述

我目前被困在我试图将图像上传到Firestore Storage并自动将图像存储URLCloud Firestore. 我试图手动将图像上传到Firebase Storage并粘贴图像 url,Cloud Firestore然后检索它以在我的应用程序中显示图像并且它可以工作。这是我到目前为止所做的编码:

models/enter.dart


class Enter {

  final String enterId;
  final String enter;
  final String price;
  final String url;

  Enter({this.enter, this.price, @required this.enterId, this.url});

  factory Enter.fromJson(Map<String, dynamic> json){
    return Enter(
        enter: json['enter'],
        price: json['price'],
        url: json['url'],
        enterId: json['enterId']
    );
  }

  Map<String,dynamic> toMap(){
    return {
      'enter':enter,
      'price':price,
      'url':url,
      'enterId':enterId
    };
  }
}

services/firestore_service2

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:journal_app/src/models/enter.dart';

class FirestoreService2 {
  FirebaseFirestore _db = FirebaseFirestore.instance;

  //Get Entries
  Stream<List<Enter>> getEnter(){
    return _db
        .collection('enters')
        .snapshots()
        .map((snapshot) => snapshot.docs
        .map((doc) => Enter.fromJson(doc.data()))
        .toList());
  }

  //Upsert
  Future<void> setEnter(Enter enter){
    var options = SetOptions(merge:true);

    return _db
        .collection('enters')
        .doc(enter.enterId)
        .set(enter.toMap(),options);
  }

  //Delete
  Future<void> removeEnter(String enterId){
    return _db
        .collection('enters')
        .doc(enterId)
        .delete();
  }

}

provider/enter_provider.dart

import 'package:flutter/material.dart';
import 'package:journal_app/src/models/enter.dart';
import 'package:journal_app/src/services/firestore_service2.dart';
import 'package:uuid/uuid.dart';

class EnterProvider with ChangeNotifier {
  final firestoreService = FirestoreService2();
  String _enter;
  String _price;
  String _enterId;
  String _url;
  var uuid = Uuid();

  //Getters
  String get enter => _enter;
  String get price => _price;
  String get url => _url;
  Stream<List<Enter>> get enters => firestoreService.getEnter();

  //Setters
  set changeEnter(String enter){
    _enter = enter;
    notifyListeners();
  }

  set changePrice(String price){
    _price = price;
    notifyListeners();
  }

  set changeUrl(String url){
    _url = url;
    notifyListeners();
  }

  //Functions
  loadAll(Enter enter){
    if (enter != null && price != null){
      _enter =enter.enter;
      _price =enter.price;
      _url=enter.url;
      _enterId = enter.enterId;
    } else {
      _enter = null;
      _price = null;
      _url = null;
      _enterId = null;
    }
  }

  saveEnter(){
    if (_enterId == null){
      //Add
      var newEnter = Enter(enter: _enter, price: _price, url: _url, enterId: uuid.v1());
      print(newEnter.enter);
      print(newEnter.price);
      print(newEnter.url);
      firestoreService.setEnter(newEnter);
    } else {
      //Edit
      var updatedEnter = Enter(enter: _enter, price: _price, url: _url, enterId: _enterId);
      firestoreService.setEnter(updatedEnter);
    }
  }

  removeEnter(String enterId){
    firestoreService.removeEnter(enterId);
  }

}

screens/enter.dart用户在其中插入产品名称、价格和图片

import 'package:date_format/date_format.dart';
import 'package:flutter/material.dart';
import 'package:journal_app/src/models/enter.dart';
import 'package:journal_app/src/providers/enter_provider.dart';
import 'package:provider/provider.dart';

class EnterScreen extends StatefulWidget {
  final Enter enter;
  final Enter price;
  final Enter category;

  EnterScreen({this.enter, this.price, this.category});

  @override
  _EnterScreenState createState() => _EnterScreenState();
}

class _EnterScreenState extends State<EnterScreen> {

  final enterController = TextEditingController();
  final enterController2 = TextEditingController();

  @override
  void dispose() {
    enterController.dispose();
    enterController2.dispose();
    super.dispose();
  }

  @override
  void initState() {
    final enterProvider = Provider.of<EnterProvider>(context,listen: false);
    if (widget.enter != null){
      //Edit
      enterController.text = widget.enter.enter;
      enterController2.text = widget.enter.price;

      enterProvider.loadAll(widget.enter);
      enterProvider.loadAll(widget.price);
    } else {
      //Add
      enterProvider.loadAll(null);
    }
    super.initState();
  }


  @override
  Widget build(BuildContext context) {
    final enterProvider = Provider.of<EnterProvider>(context);
    return Scaffold(
      appBar: AppBar(title: Text('Products')),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: ListView(
          children: [
            TextField(
              decoration: InputDecoration(
                labelText: 'Product Name', border: InputBorder.none,
              ),
              style: TextStyle(color: Colors.black, fontSize: 25),
              maxLines: 5,
              minLines: 2,
              onChanged: (String value) => enterProvider.changeEnter = value,
              controller: enterController,
            ),
            TextField(
              decoration: InputDecoration(
                labelText: 'Product Price', border: InputBorder.none,
              ),
              style: TextStyle(color: Colors.black, fontSize: 25),
              maxLines: 5,
              minLines: 2,
              onChanged: (String value) => enterProvider.changePrice = value,
              controller: enterController2,
            ),
            RaisedButton(
              color: Theme.of(context).accentColor,
              child: Text('Save',style: TextStyle(color: Colors.white, fontSize: 20)),
              onPressed: () {
                enterProvider.saveEnter();
                Navigator.of(context).pop();
              },
            ),
            (widget.enter != null) ? RaisedButton(
              color: Colors.red,
              child: Text('Delete',style: TextStyle(color: Colors.white, fontSize: 20)),
              onPressed: () {
                enterProvider.removeEnter(widget.enter.enterId);
                Navigator.of(context).pop();
              },
            ): Container(),
          ],
        ),
      ),
    );
  }
}

screens/product.dart此屏幕在列表视图中显示产品名称、价格和图像

import 'package:date_format/date_format.dart';
import 'package:flutter/material.dart';
import 'package:journal_app/src/models/enter.dart';
import 'package:journal_app/src/providers/enter_provider.dart';
import 'package:journal_app/src/screens/enter.dart';
import 'package:provider/provider.dart';

class ProductScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final enterProvider = Provider.of<EnterProvider>(context);
    return Scaffold(
      appBar: AppBar(
        title: Text('Products'),
      ),
      body: StreamBuilder<List<Enter>>(
          stream: enterProvider.enters,
          builder: (context, snapshot) {
            return ListView.builder(
                itemCount: snapshot.data.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    leading: Image.network(
                      snapshot.data[index].url,
                      width: 100,
                      height: 100,
                      fit: BoxFit.fitWidth,
                    ),
                    trailing:
                    Icon(Icons.edit, color: Theme.of(context).accentColor),
                    title: Text(
                      snapshot.data[index].enter, style: TextStyle(fontSize: 25),
                    ),
                    subtitle: Text(
                      snapshot.data[index].price,
                    ),
                    onTap: () {
                      Navigator.of(context).push(MaterialPageRoute(
                          builder: (context) =>
                              EnterScreen(enter: snapshot.data[index], price: snapshot.data[index])));
                    },
                  );
                });
          }),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          Navigator.of(context)
              .push(MaterialPageRoute(builder: (context) => EnterScreen()));
        },
      ),
    );
  }
}

目标是upload图像到Firebase Storage,存储新图像image url的同时。uploading

我需要这个项目的建议。

标签: firebaseflutterdartgoogle-cloud-firestore

解决方案


要将图像上传到 Firebase 存储并将其保存在 Cloud Firestore 中,您需要执行以下操作:

第 1 步:获取您要上传的图像为此,您可以使用image_picker包它会给您一个PickedFile对象(假设它是pickFile)。File使用以下代码将此对象转换为对象:

final file = File(pickedFile.path);

第 2 步:将此文件上传到 Firebase 存储:为您要上传的图片指定一个唯一名称。

final imageName = '${DateTime.now().millisecondsSinceEpoch}.png';

创建 Firebase 存储参考:

final firebaseStorageRef = FirebaseStorage.instance
        .ref()
        .child('images/$imageName'); // This will create a images directory in Firebase storage & save your image in that directory

开始上传图片:

final uploadTask = firebaseStorageRef.putFile(file);
final taskSnapshot = await uploadTask.onComplete;

获取图片地址:

final _fileURL = await taskSnapshot.ref.getDownloadURL();

将此图像 URL 保存在 Cloud Firestore 中。

// This will save the image in "images" collection & update the "uploadedImage" value of document with id the same as the value of "id" variable. 
await FirebaseFirestore.instance.collection(images).doc(id).update({'uploadedImage': _fileURL});

如果您要更新现有对象,请使用该update方法,否则您可以使用该set方法。


推荐阅读