firebase - 如何将图像上传到 Firebase Storage 并自动存储在 Cloud Firestore 中?
问题描述
我目前被困在我试图将图像上传到Firestore Storage
并自动将图像存储URL
到Cloud 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
我需要这个项目的建议。
解决方案
要将图像上传到 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
方法。
推荐阅读
- sycl - sycl/dpc++ 访问器与内核函数对象中的 global_ptr
- javascript - 防止内容在 css 位置更改时跳转/闪烁(绝对默认)
- java - 如何使用抽象弹簧服务的多态性?
- javascript - Javascript Brackets IDE 在 JQuery 3.5.1 文件中显示错误
- c# - 从 BotFramework Adapter 在团队中创建消息时出现问题
- entity-framework - 当对象 ID 在保存到数据库之前未设置但您在创建方法中检查了不变量时,如何进行单元测试?
- tensorflow - Tensorflow Estimator Hook 访问传递给 model_fn 的特征标签和在 model_fn 期间构建的图形操作
- javascript - 仅在 Vanilla JavaScript 中定位此父母的孩子
- c++ - 为什么我的电影类在创建电影实例时遇到问题?
- c# - 如何在我的 DbContext 中获取 IConfiguration 实例?