gpt4 book ai didi

Flutter:Streambuilder 导致 Firestore 上的读取过多

转载 作者:行者123 更新时间:2023-12-03 13:29:10 25 4
gpt4 key购买 nike

我正在尝试构建一个简单的引号 Flutter 应用程序,在其中显示引号列表并允许用户“喜欢”引号。为此,我正在使用 Streambuilder。我的问题是 Firestore 使用仪表板显示的读取次数非常多(每个用户几乎 300 次),即使我最多有 50 个引号。我有一种预感,我的代码中的某些内容导致 Streambuilder 多次触发(可能是用户“喜欢”一个报价),而且 Streambuilder 正在加载所有报价,而不仅仅是那些在用户视口(viewport)中的报价。任何有关如何解决此问题以减少读取次数的帮助将不胜感激。

import 'dart:convert';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:positivoapp/utilities.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:share/share.dart';


class QuotesScreen extends StatefulWidget {
@override
QuotesScreenLayout createState() => QuotesScreenLayout();
}

class QuotesScreenLayout extends State<QuotesScreen> {
List<String> quoteLikeList = new List<String>();

// Get Goals from SharedPrefs
@override
void initState() {
super.initState();
getQuoteLikeList();
}

Future getQuoteLikeList() async {
if (Globals.globalSharedPreferences.getString('quoteLikeList') == null) {
print("No quotes liked yet");
return;
}

String quoteLikeListString =
Globals.globalSharedPreferences.getString('quoteLikeList');
quoteLikeList = List.from(json.decode(quoteLikeListString));
setState(() {});
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
padding: const EdgeInsets.all(10.0),
child: StreamBuilder<QuerySnapshot>(
stream: Firestore.instance
.collection(FireStoreCollections.QUOTES)
.orderBy('timestamp', descending: true)
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError)
return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Row(
mainAxisSize: MainAxisSize.min,
children: [
new CircularProgressIndicator(),
new Text("Loading..."),
],
);
default:
print('Loading Quotes Stream');
return new ListView(
children: snapshot.data.documents
.map((DocumentSnapshot document) {
return new QuoteCard(
quote:
Quote.fromMap(document.data, document.documentID),
quoteLikeList: quoteLikeList,
);
}).toList(),
);
}
},
)),
),
);
}
}

class QuoteCard extends StatelessWidget {
Quote quote;
final _random = new Random();
List<String> quoteLikeList;

QuoteCard({@required this.quote, @required this.quoteLikeList});

@override
Widget build(BuildContext context) {
bool isLiked = false;
String likeText = 'LIKE';
IconData icon = Icons.favorite_border;
if (quoteLikeList.contains(quote.quoteid)) {
icon = Icons.favorite;
likeText = 'LIKED';
isLiked = true;
}

return Center(
child: Card(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
constraints: new BoxConstraints.expand(
height: 350.0,
width: 400,
),
child: Stack(children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.25), BlendMode.darken),
image: AssetImage('images/${quote.imageName}'),
fit: BoxFit.cover,
),
),
),
Center(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Text(
quote.quote,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30.0,
fontFamily: 'bold',
fontWeight: FontWeight.bold,
color: Color.fromRGBO(255, 255, 255, 1)),
),
),
),
]),
),
Padding(
padding: EdgeInsets.fromLTRB(18, 10, 10, 0),
child: Text(
'Liked by ${quote.numLikes} happy people',
textAlign: TextAlign.left,
style: TextStyle(
fontFamily: 'bold',
fontWeight: FontWeight.bold,
color: Colors.black),
),
),
ButtonBar(
alignment: MainAxisAlignment.start,
children: <Widget>[
FlatButton(
child: UtilityFunctions.buildButtonRow(Colors.red, icon, likeText),
onPressed: () async {
// User likes / dislikes this quote, do 3 things
// 1. Save like list to local storage
// 2. Update Like number in Firestore
// 3. Toggle isLiked
// 4. Setstate - No need

// Check if the quote went from liked to unlike or vice versa

if (isLiked == false) {
// False -> True, increment, add to list
quoteLikeList.add(quote.quoteid);

Firestore.instance
.collection(FireStoreCollections.QUOTES)
.document(quote.documentID)
.updateData({'likes': FieldValue.increment(1)});

isLiked = true;
} else {
// True -> False, decrement, remove from list
Firestore.instance
.collection(FireStoreCollections.QUOTES)
.document(quote.documentID)
.updateData({'likes': FieldValue.increment(-1)});
quoteLikeList.remove(quote.quoteid);

isLiked = false;
}

// Write to local storage
String quoteLikeListJson = json.encode(quoteLikeList);
print('Size of write: ${quoteLikeListJson.length}');
Globals.globalSharedPreferences.setString(
'quoteLikeList', quoteLikeListJson);

// Guess setState(); will happen via StreamBuilder - Yes
// setState(() {});
},
),
],
),
],
),
),
);
}
}

最佳答案

你的预感是正确的。由于您的 Streambuilder 在您的 Build 方法中,因此每次重新构建小部件树时都会在 Firestore 上进行读取。这比我能解释得更好here .

为防止这种情况发生,您应该在 initState 方法中收听 Firestore 流。这样它只会被调用一次。像这样 :

class QuotesScreenLayout extends State<QuotesScreen> {
List<String> quoteLikeList = new List<String>();
Stream yourStream;

// Get Goals from SharedPrefs
@override
void initState() {
yourStream = Firestore.instance
.collection(FireStoreCollections.QUOTES)
.orderBy('timestamp', descending: true)
.snapshots();

super.initState();
getQuoteLikeList();
}

Future getQuoteLikeList() async {
if (Globals.globalSharedPreferences.getString('quoteLikeList') == null) {
print("No quotes liked yet");
return;
}

String quoteLikeListString =
Globals.globalSharedPreferences.getString('quoteLikeList');
quoteLikeList = List.from(json.decode(quoteLikeListString));
setState(() {});
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
padding: const EdgeInsets.all(10.0),
child: StreamBuilder<QuerySnapshot>(
stream: yourStream,
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {

关于Flutter:Streambuilder 导致 Firestore 上的读取过多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62226143/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com