#flutter #google-cloud-firestore #stream-builder
#flutter #google-cloud-firestore #stream-builder
Вопрос:
Я использую streambuilder для прослушивания изменений из базы данных firestore и обновления моего виджета. Однако моя проблема в том, что я использую несколько ручных setstates для внесения визуальных изменений в свой код при нажатии кнопки, и эти setstates также запускают setstate streambuilder и показывают пользователям дополнительный экран загрузки. Как я могу получить отдельные setstates? Должен ли я использовать что-то другое вместо streambuilder?
Мой код приведен ниже:
import 'package:flutter/material.dart';
import 'package:assets_audio_player/assets_audio_player.dart';
import 'numbers.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
Numbers myNumbers = Numbers();
void main(){
runApp(
GameScreen()
);
}
class GameScreen extends StatefulWidget {
static String id ='gamescreen';
@override
_GameScreenState createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen> {
bool _initialized = false;
bool _error = false;
void initializeFlutterFire() async {
try {
// Wait for Firebase to initialize and set `_initialized` state to true
await Firebase.initializeApp();
setState(() {
_initialized = true;
});
} catch(e) {
// Set `_error` state to true if Firebase initialization fails
setState(() {
_error = true;
});
}
}
@override
void initState() {
initializeFlutterFire();
super.initState();
getCurrentUser();
}
final _auth =FirebaseAuth.instance;
User loggedInUser;
final _firestore = FirebaseFirestore.instance;
final String collectionPath = 'users';
String docPath;
DocumentReference userdoc;
void getCurrentUser() async{
try{
final user = await _auth.currentUser;
if(user !=null){
loggedInUser =user;
docPath = loggedInUser.uid;
}
}catch(e){
print(e);
}
}
Expanded attachNumber(imagenumber){
return Expanded(
child:FlatButton(
onPressed: (){
setState(() {
if(!myNumbers.numberStatus[1]){
myNumbers.buttonValues['numberimage1'] = imagenumber;
myNumbers.numberStatus[1] =true;
}else if(!myNumbers.numberStatus[2]){
myNumbers.buttonValues['numberimage2'] = imagenumber;
myNumbers.numberStatus[2] =true;
}else if(!myNumbers.numberStatus[3]){
myNumbers.buttonValues['numberimage3'] = imagenumber;
myNumbers.numberStatus[3] =true;
}else if(!myNumbers.numberStatus[4]){
myNumbers.buttonValues['numberimage4'] = imagenumber;
myNumbers.numberStatus[4] =true;
}
});
final assetsAudioPlayer = AssetsAudioPlayer();
assetsAudioPlayer.open(
Audio("assets/audios/click.wav"),
);
},
padding: EdgeInsets.all(0),
child: Image.asset('images/$imagenumber'),
),
);
}
FlatButton showDeleteNumbers(statusNumber,number){
return FlatButton(
onPressed: (){
setState(() {
myNumbers.numberStatus[statusNumber] =false;
myNumbers.buttonValues[number] = 'nonumber.png';
});
},
child: Image.asset('images/' myNumbers.buttonValues['$number']),
);
}
@override
Widget build(BuildContext context) {
userdoc = _firestore.collection(collectionPath).doc(docPath);
if(_error) {
return Text('error-game', textDirection: TextDirection.ltr);
}
// Show a loader until FlutterFire is initialized
if (!_initialized) {
return Text('Loading', textDirection: TextDirection.ltr);
}
return StreamBuilder<DocumentSnapshot>(
stream: userdoc.snapshots(),
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
if(snapshot.hasData){
Map<String, dynamic> userDocument = snapshot.data.data();
print(collectionPath);
print(docPath);
print(snapshot.data);
print(userDocument);
return MaterialApp(
home:Scaffold(
appBar: AppBar(
backgroundColor: Colors.amberAccent,
title: Text('Sayı Avı Oyun Ekranı'),
),
body:Column(
children: <Widget>[
Expanded(
flex: 80,
child: Row(
children: <Widget>[
Expanded(
flex: 50,
child: Column(
children: myNumbers.getUserNumbers(),
),
),
Expanded(
flex: 50,
child: Column(
children: myNumbers.getOpponentNumbers(),
),
),
],
),
),
Expanded(
flex:10,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
showDeleteNumbers(1,'numberimage1'),
showDeleteNumbers(2,'numberimage2'),
showDeleteNumbers(3,'numberimage3'),
showDeleteNumbers(4,'numberimage4'),
],
),
),
Expanded(
flex: 10,
child: Row(
children: <Widget>[
attachNumber('one.png'),
attachNumber('two.png'),
attachNumber('three.png'),
attachNumber('four.png'),
attachNumber('five.png'),
attachNumber('six.png'),
attachNumber('seven.png'),
attachNumber('eight.png'),
attachNumber('nine.png'),
attachNumber('zero.png'),
],
),
),
],
),
),
);
}
},
);
}
}
Ответ №1:
Попробуйте записать поток userdoc.snapshots()
в переменную в initState вместо вызова метода snapshots в каждой сборке. Таким образом, вы убедитесь, что streambuilder получает один и тот же поток при каждой сборке и, следовательно, может поддерживать свое состояние, если вы его перестроите