添加数据时,Firebase 列表视图未实时显示

Firebase List view is not displayed in real-time while adding data

从 phone 中选择联系人后,我将联系人信息存储在 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();
  }
}

问题是这部分:

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);
        });