为啥 Firebase 实时数据库的数据在控制台中显示为空?
Posted
技术标签:
【中文标题】为啥 Firebase 实时数据库的数据在控制台中显示为空?【英文标题】:Why is the Firebase Realtime Database's data appearing as null in the console?为什么 Firebase 实时数据库的数据在控制台中显示为空? 【发布时间】:2021-09-02 15:35:36 【问题描述】:我正在尝试创建一个简单的应用程序,该应用程序将帖子添加到 firebase 实时数据库并在颤动的列表视图中显示它们,但是当我将其“发布”到数据库时,在 firebase 控制台上,数据值不断显示为空值。有谁知道怎么回事?
这是我的一些代码 -
post.dart
class Post
Image coverImg;
File audioFile;
String body;
String author;
Set usersLiked = ;
DatabaseReference _id;
Post(this.body, this.author);
void likePost(User user)
if (this.usersLiked.contains(user.uid))
this.usersLiked.remove(user.uid);
else
this.usersLiked.add(user.uid);
void update()
updatePost(this, this._id);
void setId(DatabaseReference id)
this._id = id;
Map<String, dynamic> toJson()
return
'body': this.body,
'author': this.author,
'usersLiked': this.usersLiked.toList()
;
Post createPost(record)
Map<String, dynamic> attributes =
'author': '',
'usersLiked': [],
'body': ''
;
record.forEach((key, value) => attributes[key] = value);
Post post = new Post(attributes['body'], attributes['author']);
post.usersLiked = new Set.from(attributes['usersLiked']);
return post;
class PostList extends StatefulWidget
final List<Post> listItems;
final User user;
PostList(this.listItems, this.user);
@override
_PostListState createState() => _PostListState();
class _PostListState extends State<PostList>
void like(Function callBack)
this.setState(()
callBack();
);
@override
void initState()
super.initState();
@override
void dispose()
super.dispose();
@override
Widget build(BuildContext context)
return ListView.builder(
itemCount: this.widget.listItems.length,
itemBuilder: (context, index)
var post = this.widget.listItems[index];
return Card(
elevation: 7.0,
color: Colors.white,
child: Column(
children: [
Row(
children: [
IconButton(
icon: Icon(
Icons.play_circle_outline,
color: Colors.black,
size: 30,
),
onPressed: () ,
),
Expanded(
child: ListTile(
title: Text(post.body,
style: TextStyle(
fontWeight: FontWeight.w600,
color: Colors.black)),
subtitle: Text(post.author,
style: TextStyle(color: Colors.black)),
),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(post.usersLiked.length.toString(),
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600)),
IconButton(
icon: Icon(
Icons.thumb_up,
color: post.usersLiked.contains(widget.user.uid)
? Colors.blue
: Colors.black,
),
onPressed: () =>
this.like(() => post.likePost(widget.user)),
)
],
))
],
)
],
));
,
);
database.dart
final databaseReference = FirebaseDatabase.instance.reference();
DatabaseReference savePost(Post post)
var id = databaseReference.child('posts/').push();
id.set(post.toJson());
return id;
void updatePost(Post post, DatabaseReference id)
id.update(post.toJson());
Future<List<Post>> getAllPosts() async
DataSnapshot dataSnapshot = await databaseReference.child('posts/').once();
List<Post> posts = [];
if (dataSnapshot.value != null)
dataSnapshot.value.forEach((key, value)
Post post = createPost(value);
post.setId(databaseReference.child('posts/' + key));
posts.add(post);
);
return posts;
home.dart
class UserInfoScreen extends StatefulWidget
const UserInfoScreen(Key key, User user)
: _user = user,
super(key: key);
final User _user;
@override
_UserInfoScreenState createState() => _UserInfoScreenState();
class _UserInfoScreenState extends State<UserInfoScreen>
User _user;
bool _isSigningOut = false;
List<Post> posts = [];
void newPost(String text)
var post = new Post(text, widget._user.displayName);
post.setId(savePost(post));
this.setState(()
posts.add(post);
);
void updatePosts()
getAllPosts().then((posts) =>
this.setState(()
this.posts = posts;
)
);
Route _routeToSignInScreen()
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => SignInScreen(),
transitionsBuilder: (context, animation, secondaryAnimation, child)
var begin = Offset(-1.0, 0.0);
var end = Offset.zero;
var curve = Curves.ease;
var tween =
Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
return SlideTransition(
position: animation.drive(tween),
child: child,
);
,
);
@override
void initState()
_user = widget._user;
// HOME PAGE
pageList.add(Scaffold(
backgroundColor: Colors.white,
body: Column(children: [
Expanded(
child: PostList(this.posts, _user),
),
]),
));
pageList.add(Test1());
pageList.add(Scaffold(
backgroundColor: Colors.white,
body: Column(
children: [
TextInputWidget(this.newPost, "Title:"),
],
),
));
pageList.add(Test3());
// ACCOUNT PAGE
pageList.add(
Scaffold(
backgroundColor: Colors.white,
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(),
_user.photoURL != null
? ClipOval(
child: Material(
color: Colors.grey.withOpacity(0.3),
child: Image.network(
_user.photoURL,
fit: BoxFit.fitHeight,
),
),
)
: ClipOval(
child: Material(
color: Colors.grey.withOpacity(0.3),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Icon(
Icons.person,
size: 60,
color: Colors.black,
),
),
),
),
SizedBox(height: 16.0),
Text(
'$_user.displayName',
style: TextStyle(
color: Colors.black,
fontSize: 26,
fontWeight: FontWeight.w700),
),
SizedBox(height: 8.0),
Text(
' $_user.email ',
style: TextStyle(
color: Colors.black,
fontSize: 20,
letterSpacing: 0.5,
),
),
SizedBox(height: 60.0),
_isSigningOut
? CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
)
: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Colors.redAccent,
),
shape: MaterialStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
),
onPressed: () async
setState(()
_isSigningOut = true;
);
await Authentication.signOut(context: context);
setState(()
_isSigningOut = false;
);
Navigator.of(context)
.pushReplacement(_routeToSignInScreen());
,
child: Padding(
padding: EdgeInsets.only(top: 8.0, bottom: 8.0),
child: Text(
'Logout',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
),
),
],
),
),
);
super.initState();
updatePosts();
@override
List<Widget> pageList = List<Widget>();
int _currentIndex = 0;
void onTabTapped(int index)
setState(()
_currentIndex = index;
);
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
elevation: 0.0,
backgroundColor: Colors.white,
title: Text(
'SoundFX',
style: TextStyle(color: Colors.black),
),
centerTitle: true,
),
body: IndexedStack(
index: _currentIndex,
children: pageList,
),
bottomNavigationBar: BottomNavigationBar(
unselectedItemColor: Colors.grey,
selectedItemColor: Colors.blue,
backgroundColor: Colors.white,
elevation: 19.0,
onTap: onTabTapped,
currentIndex: _currentIndex,
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: new Icon(Icons.home),
title: Container(
height: 1.0,
)),
BottomNavigationBarItem(
icon: new Icon(Icons.search),
title: Container(
height: 1.0,
)),
BottomNavigationBarItem(
icon: new Icon(
Icons.add_circle,
size: 40,
),
title: Container(
height: 1.0,
)),
BottomNavigationBarItem(
icon: new Icon(Icons.videocam),
title: Container(
height: 1.0,
)),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle),
title: Container(
height: 1.0,
)),
],
),
);
class Test1 extends StatelessWidget
@override
Widget build(BuildContext context)
return Container(
color: Colors.green,
);
class Test2 extends StatelessWidget
@override
Widget build(BuildContext context)
return Container(
color: Colors.blue,
);
class Test3 extends StatelessWidget
@override
Widget build(BuildContext context)
return Container(
color: Colors.yellow,
);
text-input.dart
class TextInputWidget extends StatefulWidget
final Function(String) callback;
String label;
TextInputWidget(this.callback, this.label);
@override
_TextInputWidgetState createState() => _TextInputWidgetState();
class _TextInputWidgetState extends State<TextInputWidget>
final controller = TextEditingController();
@override
void dispose()
super.dispose();
controller.dispose();
void click()
widget.callback(controller.text);
FocusScope.of(context).unfocus();
controller.clear();
void pickFiles() async
FilePickerResult result =
await FilePicker.platform.pickFiles(type: FileType.any);
File file = File(result.files.first.path);
print(file);
@override
Widget build(BuildContext context)
return Container(
height: 400,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: Container(
padding: EdgeInsets.all(20.0),
child: TextField(
controller: this.controller,
decoration: InputDecoration(
labelText: this.widget.label,
))),
),
Container(
child: ElevatedButton(onPressed: this.click, child: Text('Post')),
),
Container(
child:
ElevatedButton(onPressed: this.pickFiles, child: Text('test')),
)
],
),
);
PS:另外,请注意,有些函数和类是未使用或基本没用的,有些名称非常愚蠢,但如果它们与问题无关,请不要评论,因为那些只是对我要添加到应用程序中的功能进行一些测试。
另外,请注意我遵循了本教程 - https://www.youtube.com/playlist?list=PLzMcBGfZo4-knQWGK2IC49Q_5AnQrFpzv
【问题讨论】:
我会看看会发生什么,但遵循 how to create a minimal, complete, verifiable example 中的指导确实是您可以做的最好的事情,以增加有人可以提供帮助的机会。 通过快速扫描,这是我看到您写入数据库的主要位置:id.set(post.toJson());
。 1)当该行运行时,是否有任何内容写入调试输出? 2) 如果将其更改为id.set("hello world");
,它会写入数据库吗? 3)id.update(post.toJson());
中的id
在哪里定义?
@FrankvanPuffelen 1) 不,我什么都没看到,2) 更改后什么也没写,3) id 直接在 database.dart 的 savePost() 函数中定义
3) 我问过updatePost
;-) 1) 嗯...您确定您的设备已连接到网络/数据库吗?如果是这样,您的数据库在哪里?
@FrankvanPuffelen 哈哈,抱歉,在 updatePost 中它位于 Post 类中。嗯,你说的连接是什么意思?我正在使用 ios 模拟器,很明显,我的网络正在运行。但是我的数据库位于新加坡,或者 asia-southeast1
【参考方案1】:
firebaser 在这里
Firebase SDK 很可能无法从其配置文件中读取数据库的 URL,因为您的数据库托管在默认(美国)区域之外。
如果确实是这个原因,您应该在代码中指定数据库 URL。通过在代码中指定它,SDK 应该能够连接到数据库实例,无论它托管在哪个区域。
这意味着你应该得到你的数据库
FirebaseDatabase("your database URL").reference()
// Or
FirebaseDatabase(databaseURL: "your database URL").reference()
而不是
FirebaseDatabase.instance.reference()
此已记录在here:
要获取对 us-central1 默认 dstabase 以外的数据库的引用,您必须将数据库 URL 传递给 getInstance()(或 Kotlin+KTX database())。对于 us-central1 默认数据库,您可以不带参数调用 getInstance()(或数据库)。
因此,虽然这个 已记录在案,但它非常容易被忽视。我正在与我们的团队确认是否有什么办法可以让这个配置问题更加明显。
【讨论】:
哇!太感谢了。是的,它确实有效,但由于某种原因,这些帖子没有显示在列表视图中......你知道可能是什么问题吗? 这似乎是一个不同的问题,所以我建议使用自己的minimal reproduction 发布一个新问题。以上是关于为啥 Firebase 实时数据库的数据在控制台中显示为空?的主要内容,如果未能解决你的问题,请参考以下文章
为啥注册用户后 Firebase 实时数据库用户 ID 与 Firebase 身份验证 UID 不匹配?