Я пытаюсь читать данные в реальном времени из моей базы данных firebase firestore через флаттер. Я узнал, что лучший способ справиться с этим - это streambuilder. Проверил несколько сайтов по этой теме и сделал код, как показано ниже, и поместил оператор печати, чтобы посмотреть, все ли работает нормально, однако, когда я запускаю программу, она выдает следующие ошибки:
A build function returned null.
The relevant error-causing widget was:
StreamBuilder<DocumentSnapshot> file:///C:/Users/faruk/Desktop/3-sayiavi/sayi_avi/lib/gamescreen.dart:116:15
The method '[]' was called on null.
Receiver: null
Tried calling: []("status")
The relevant error-causing widget was:
StreamBuilder<DocumentSnapshot> file:///C:/Users/faruk/Desktop/3-sayiavi/sayi_avi/lib/gamescreen.dart:116:15
Мой код ниже:
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';
Numbers myNumbers = Numbers();
void main(){
runApp(
GameScreen()
);
}
class GameScreen extends StatefulWidget {
static String id ='gamescreen';
@override
_GameScreenState createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen> {
final _auth =FirebaseAuth.instance;
FirebaseUser loggedInUser;
final _firestore = Firestore.instance;
String collectionPath = 'users';
String docPath;
@override
void initState(){
super.initState();
getCurrentUser();
}
void getCurrentUser() async{
try{
final user = await _auth.currentUser();
if(user !=null){
loggedInUser =user;
docPath = loggedInUser.uid;
print(docPath);
print(collectionPath);
}
}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']),
//todo: _auth.signOut(); ekleyerek signout yapacaz
//Navigator.pop(context); bir önceki ekrana dönecez;
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.amberAccent,
title: Text('Sayı Avı Oyun Ekranı'),
),
body: StreamBuilder(
stream: _firestore.collection(collectionPath).document(docPath).snapshots(),
builder: (context,snapshot){
if(snapshot.hasData){
var userDocument = snapshot.data;
print(userDocument['status']);
return 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'),
],
),
),
],
);
}
},
),
),
);
}
}
изменил код следующим образом:
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';
Numbers myNumbers = Numbers();
void main(){
runApp(
GameScreen()
);
}
class GameScreen extends StatefulWidget {
static String id ='gamescreen';
@override
_GameScreenState createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen> {
final _auth =FirebaseAuth.instance;
FirebaseUser loggedInUser;
final _firestore = Firestore.instance;
String collectionPath = 'users';
String docPath;
@override
void initState(){
super.initState();
getCurrentUser();
}
void getCurrentUser() async{
try{
final user = await _auth.currentUser();
if(user !=null){
loggedInUser =user;
docPath = loggedInUser.uid;
print(docPath);
print(collectionPath);
}
}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']),
//todo: _auth.signOut(); ekleyerek signout yapacaz
//Navigator.pop(context); bir önceki ekrana dönecez;
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.amberAccent,
title: Text('Sayı Avı Oyun Ekranı'),
),
body: StreamBuilder<DocumentSnapshot>(
stream: _firestore.collection(collectionPath).document(docPath).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(userDocument);
return 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'),
],
),
),
],
);
}
},
),
),
);
}
}
В настоящее время он получает значения карты, когда я нажимаю кнопку «Сохранить», но когда я возвращаюсь назад и вперед в avd, он снова получает значение null. Что может быть не так?
то, что я хотел бы сделать, это функция firebase, которая сопоставляет пользователей в соответствии с их статусом в базе данных. когда пользователь входит в этот экран, его статус будет включен в базе данных, и когда функция firebase найдет другого пользователя со статусом on, она сделает их статус готовыми или что-то в этом роде. Когда статус пользователя изменится на «Готов», вместо отображения, например, экрана поиска матча, он изменится на экран игры, и 2 человека начнут играть по очереди. Итак, чтобы подвести итог, как только пользователь входит в этот экран, он должен начать прослушивать изменения своего статуса. Кроме того, поскольку это будет пошаговая игра, она должна продолжить прослушивание других полей на предмет изменений базы данных. Надеюсь, я мог объяснить себя.
Обновлен код flutter firebase для новых зависимостей ниже
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';
Numbers myNumbers = Numbers();
void main(){
runApp(
GameScreen()
);
}
class GameScreen extends StatefulWidget {
static String id ='gamescreen';
@override
_GameScreenState createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen> {
final _auth =FirebaseAuth.instance;
User loggedInUser;
final _firestore = FirebaseFirestore.instance;
final String collectionPath = 'users';
String docPath;
DocumentReference userdoc;
@override
void initState(){
super.initState();
getCurrentUser();
}
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);
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'),
],
),
),
],
),
),
);
}
},
);
}
}
Вы можете увидеть, что есть 4 отпечатка, чтобы проверить, правильно ли я получаю данные. В настоящее время, когда я запускаю приложение, оно показывает
I / flutter (15703): пользовательский I / flutter (15703): viPK8SpL9MOIV2bQqGzBkKVdYAk2 I / flutter (15703): Экземпляр I / flutter 'DocumentSnapshot' (15703): null
Четвертый не должен быть нулевым, когда я нажимаю кнопку сохранения в студии Android, я получаю
I / flutter (15703): пользователи I / flutter (15703): viPK8SpL9MOIV2bQqGzBkKVdYAk2 I / flutter (15703): экземпляр DocumentSnapshot I / flutter (15703): {пароль: 123456, проигрыш: 0: победа: 0, адрес эл. [email protected], статус: готов}
Что и есть правильный результат.