添加数据时,Firebase 列表视图未实时显示
Posted
技术标签:
【中文标题】添加数据时,Firebase 列表视图未实时显示【英文标题】:Firebase List view is not displayed in real-time while adding data 【发布时间】:2021-08-13 03:07:54 【问题描述】:从电话中选择联系人后,我将联系人信息存储在 Firebase 实时数据库中。 当我添加使用 ListView 和 DataSnapshot 显示的数据时,数据不会实时刷新,直到我重新启动 Activity。 ListView 加载并显示所有数据没有任何问题。我该如何解决这个问题?
我的屏幕是这样的:
屏幕代码:
import 'package:epicare/CaregiverClass.dart';
import 'package:epicare/Homepage.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_switch/flutter_switch.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:contact_picker/contact_picker.dart';
//Check contacts permission
Future<PermissionStatus> _getPermission() async
final PermissionStatus permission = await Permission.contacts.status;
if (permission != PermissionStatus.granted &&
permission != PermissionStatus.denied)
final Map<Permission, PermissionStatus> permissionStatus =
await [Permission.contacts].request();
return permissionStatus[Permission.contacts] ??
PermissionStatus.undetermined;
else
return permission;
class CaregiverScreen extends StatefulWidget
@override
_CaregiverScreenState createState() => _CaregiverScreenState();
class _CaregiverScreenState extends State<CaregiverScreen>
//Firebase
FirebaseAuth firebaseAuth = FirebaseAuth.instance;
final ref = FirebaseDatabase.instance.reference();
User cuser = FirebaseAuth.instance.currentUser;
final fb = FirebaseDatabase.instance.reference().child("User_data");
List <CaregiverList> list = List();
// Adding data into Firebase
void addData(String name, String number)
print("Saving data to firebase");
ref.child('User_data').child(cuser.uid).child("caregivers").push().set('Caregiver_Name': name, 'Caregiver_Number': number);
// Get location
Position _currentPosition;
String _currentAddress;
final Geolocator geolocator = Geolocator()..forceandroidLocationManager;
@override
void initState()
// Firebase
fb.child(cuser.uid).child("caregivers").once().then((DataSnapshot snapshot)
var data = snapshot.value;
list.clear();
data.forEach((key,value)
print(value['Caregiver_Name']);
CaregiverList contact_list = new CaregiverList(
name: value['Caregiver_Name'],
phone_number: value['Caregiver_Number'],
isActive: true,
key: key,
);
list.add(contact_list);
);
setState(()
);
);
super.initState();
final ContactPicker _contactPicker = new ContactPicker();
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context)
//Size size = MediaQuery.of(context).size;
return Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: const Color(0xffE5E0A1),
elevation: 0,
centerTitle: true,
title: Text(
"Add Caregiver",
style: TextStyle(
fontSize: 15.0,
color: Colors.black,
fontFamily: 'Montserrat',
fontWeight: FontWeight.normal,
),
),
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: ()
Navigator.push(
context,
MaterialPageRoute(
builder: (context)
return Homepage();
,
),
);
,
),
),
body: SingleChildScrollView(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 40),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
MaterialButton(
onPressed: () async
final PermissionStatus permissionStatus =
await _getPermission();
if (permissionStatus == PermissionStatus.granted)
//We can now access our contacts here
Contact contact = await _contactPicker.selectContact();
print("Contact name: $contact.fullName");
print("Contact number: $contact.phoneNumber");
List<String> num =
contact.phoneNumber.toString().split('(Work)');
print(num);
print(num[0]);
final pattern = RegExp('\\s+');
num[0].replaceAll(pattern, '');
num[0].replaceAll(new RegExp('-'),'');
addData(contact.fullName.toString(),num[0]);
else
//If permissions have been denied show standard cupertino alert dialog
showDialog(
context: context,
builder: (BuildContext context) =>
CupertinoAlertDialog(
title: Text('Permissions error'),
content: Text('Please enable contacts access '
'permission in system settings'),
actions: <Widget>[
CupertinoDialogAction(
child: Text('OK'),
onPressed: () =>
Navigator.of(context).pop(),
)
],
));
,
color: const Color(0xffd4d411),
textColor: Colors.white,
child: Icon(
Icons.add,
size: 32,
),
padding: EdgeInsets.all(3),
shape: CircleBorder(),
),
Text(
'Add a Caregiver',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 13,
color: const Color(0xff000000),
height: 1.5384615384615385,
fontWeight: FontWeight.w600),
textHeightBehavior:
TextHeightBehavior(applyHeightToFirstAscent: false),
textAlign: TextAlign.left,
)
],
),
list.length == 0 ? Center(child: Text("Please add Caregivers"))
: ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
primary: false,
itemBuilder: (context, index)
return _caregiverWidget(list[index].name,list[index].phone_number,list[index].isActive,list[index].key
);
,
separatorBuilder: (_, __) => Container(),
itemCount: list.length),
// _contact == null ? Container() : CaregiversList(_contact.fullName),
],
),
),
),
);
Widget _caregiverWidget( String name, String phone_number, bool isActive, String key
)
print(name);
var c = name.split(' ');
print(c[0]);
var caregiver = c[0];
var output = getInitials(string: caregiver, limitTo: 1);
print(output);
return GestureDetector(
onLongPress: (),
onTap: (),
child: Card(
elevation: 0,
child: Container(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 27),
child: Row(
//crossAxisAlignment: CrossAxisAlignment.center,
//mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CircleAvatar(
radius: 24,
backgroundColor: const Color(0xffd4d411),
child: CircleAvatar(
radius: 22,
backgroundColor: Colors.white,
child: Text(
output,
style: TextStyle(
fontFamily: 'Segoe UI',
fontSize: 20,
color: const Color(0xff000000),
),
),
),
),
SizedBox(width: 19),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
caregiver,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 13,
color: const Color(0xff000000),
height: 1.5384615384615385,
fontWeight: FontWeight.w600),
textHeightBehavior:
TextHeightBehavior(applyHeightToFirstAscent: false),
textAlign: TextAlign.left,
),
isActive
? Text(
"Activated",
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 10,
color: const Color(0x80232425),
fontWeight: FontWeight.w500),
textAlign: TextAlign.left,
)
: Text(
"Disabled",
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 10,
color: const Color(0x80232425),
fontWeight: FontWeight.w500),
textAlign: TextAlign.left,
),
],
),
SizedBox(width: 143),
FlutterSwitch(
width: 40.0,
height: 20.0,
value: isActive,
toggleSize: 15,
borderRadius: 40.0,
padding: 2.0,
showOnOff: false,
activeColor: const Color(0xffd4d411),
activeToggleColor: Colors.white,
inactiveColor: const Color(0xffDDDBAF),
inactiveToggleColor: Colors.white,
onToggle: (value)
print(value);
setState(()
isActive = value;
// _careList.removeAt(index);
// _careList.insert(index, _caregiver);
);
,
),
],
),
),
),
);
String getInitials(String string, int limitTo)
var buffer = StringBuffer();
var split = string.split(' ');
for (var i = 0; i < (limitTo ?? split.length); i++)
buffer.write(split[i][0]);
return buffer.toString();
【问题讨论】:
这里需要使用StreamBuilder进行实时更新。 你能告诉我如何使用它吗? 【参考方案1】:问题在于这部分:
fb.child(cuser.uid).child("caregivers").once()..
只获得一次价值。
要查看实时更新,您应该使用listener
,如下所示:
CollectionReference reference = Firestore.instance.collection('caregivers');
reference.snapshots().listen((querySnapshot)
querySnapshot.documentChanges.forEach((change)
// Do something with change
);
);
或StreamBuilder
喜欢这里:
StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('caregivers').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot)
if (!snapshot.hasData) return new Text('Loading...');
return new ListView(
children: snapshot.data.documents.map((DocumentSnapshot document)
return new ListTile(
title: new Text(document['name']),
);
).toList(),
);
,
);
对于 RTDB,StreamBuilder
如下所示:
StreamBuilder(
stream: _database.reference().child('caregivers').onValue,
builder: (context, event)
if (event.hasData &&
!event.hasError &&
event.data.snapshot.value != null)
DataSnapshot snapshot = event.data.snapshot;
)
听者会是这样的:
_database.reference().child('caregivers').onValue.listen((event)
)
onValue
每次都会为您提供整个列表,因此您需要在再次添加每个项目之前清空它:
var data = event.snapshot.value;
list= List(); //Clear the list here
data.forEach((key, value)
print(value['Caregiver_Name']);
CaregiverList contact_list = new CaregiverList(
name: value['Caregiver_Name'],
phone_number: value['Caregiver_Number'],
isActive: true,
key: key,
);
list.add(contact_list);
);
【讨论】:
我使用的是实时数据库而不是firestore 你能解释一下使用实时数据库吗? 我应该使用 Stream Builder 并删除 Listview.builder,对不起,我还是 Flutter 的新手,这就是为什么我很难理解我应该在哪里更改代码 我应该在监听器里面写什么? 我会推荐使用 StreamBuilder。替换这部分代码list.length == 0 ? Center(child: Text("Please add Caregivers")) : ListView.separated( physics: NeverScrollableScrollPhysics(), shrinkWrap: true, primary: false, itemBuilder: (context, index) return _caregiverWidget(list[index].name,list[index].phone_number,list[index].isActive,list[index].key...
以上是关于添加数据时,Firebase 列表视图未实时显示的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Firebase 实时数据库的数据在控制台中显示为空?