【发布时间】:2021-01-28 10:27:00
【问题描述】:
我正在尝试通过颤振从我的 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 函数可以根据用户在数据库中的“状态”来匹配用户。当用户进入此屏幕时,其状态将在数据库中为“on”,当 firebase 功能找到另一个具有“on”状态的用户时,它将使他们的状态为“ready”或类似的状态。当用户的状态更改为“准备就绪”而不是显示例如“正在搜索比赛”屏幕时,它将更改为游戏屏幕,并且 2 ppl 将开始基于回合进行游戏。所以总结一下,一旦用户进入这个屏幕,它就应该开始监听其状态的变化。此外,由于它将是一个回合制游戏,它应该在以后继续侦听其他字段以了解数据库更改。我希望我能解释一下自己。
为下面的新依赖项更新了颤振 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):用户 我/颤振(15703):viPK8SpL9MOIV2bQqGzBkKVdYAk2 I/flutter (15703): 'DocumentSnapshot' 的实例 我/颤振(15703):空
第 4 个不应该为空,当我在 android studio 中单击“保存”按钮时,我得到了
I/flutter (15703):用户 我/颤振(15703):viPK8SpL9MOIV2bQqGzBkKVdYAk2 I/flutter (15703): 'DocumentSnapshot' 的实例 I/flutter (15703):{密码:123456,输:0,赢:0,电子邮件:faruk@durusoy.net,状态:就绪}
哪个是正确的结果。
【问题讨论】:
-
也许添加一些其他小部件,如 CircularProgressIndicator,这可能是错误,因为数据仍在加载您的流没有返回任何小部件
-
@Reign 更改了上面的代码,当我单击保存按钮时,它会获取数据库中的所有值,但是当我在 avd 中单击后退和前进时,它会收到 null。
-
尝试直接在流中使用uid。就像流文档路径中的 _auth.currentUser().uid。
标签: flutter google-cloud-firestore stream-builder