Неправильное поведение Flutter при обновлении Firebase - PullRequest
0 голосов
/ 25 июня 2018

У меня есть код ниже, который читает baby имя и голосование от firestore и представляет информацию в Cards с помощью кнопок thump_up и thump_down.

Данные обновляются при изменениях в базе данных пожарной базы, но они обновляются неправильно, например, на снимке экрана ниже, сначала я ввел Karam данные ребенка, и они обновляются правильно, затем я ввел данные ребенка «Дана» , но он создал еще одну карту с Karam данными о ребенке (то есть, ту же, что была создана до него), но при вводе Yara данных о ребенке, здесь была создана правильная карта! Я думаю, потому что это в конце списка!

Кроме того, на последнем снимке экрана я удалил запись для Dana baby из базы данных, но была удалена последняя созданная карта, предназначенная для Yara baby !!

То же самое, когда мы нажимаем значок thumb_up, голос обновляется в базе данных, но не отражается в карточке: (

main.dart

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'BabyModel.dart';
import 'BabyCard.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  MyApp();

  @override
  State<StatefulWidget> createState() => MyAppState();
}

class MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext ctxt) {
    return StreamBuilder(
      stream: Firestore.instance.collection('baby').snapshots(),
      builder: (_, AsyncSnapshot<QuerySnapshot> snapshot) {
        var documents = snapshot.data?.documents ?? [];
        var baby =
        documents.map((snapshot) => BabyData.from(snapshot)).toList();
        return BabyPage(baby);
      },
    );
  }
}

class BabyPage extends StatefulWidget {
  final List<BabyData> allBaby;

  BabyPage(this.allBaby);

  @override
  State<StatefulWidget> createState() {
    return BabyPageState();
  }
}


class BabyPageState extends State<BabyPage> {
  @override
  Widget build(BuildContext context) {

  //  var filteredBaby = widget.allFish.where((BabyData data) {
  //    data.name = 'Dana';
  //  }).toList();

    return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: SafeArea(
        child: Scaffold(
        body: Container(
        child: ListView.builder(
            itemCount: widget.allBaby.length,
            padding: const EdgeInsets.only(top: 10.0),
            itemBuilder: (context, index) {
              return BabyCard(widget.allBaby[index]);
            })
      ),
    )));
  }
}

BabyModel.dart:

import 'package:cloud_firestore/cloud_firestore.dart';

class BabyData {
  final DocumentReference reference;
  String name;
  int vote;

  BabyData.data(this.reference,
      [this.name,
        this.vote]) {
    // Set these rather than using the default value because Firebase returns
    // null if the value is not specified.
    this.name ??= 'Frank';
    this.vote ??= 7;
  }

  factory BabyData.from(DocumentSnapshot document) => BabyData.data(
      document.reference,
      document.data['name'],
      document.data['vote']);

  void save() {
    reference.setData(toMap());
  }

  Map<String, dynamic> toMap() {
    return {
      'name': name,
      'vote': vote,
    };
  }
}

BabyCard.dart

import 'package:flutter/material.dart';
import 'BabyModel.dart';

class BabyCard extends StatefulWidget {
  final BabyData baby;

  BabyCard(this.baby);

  @override
  State<StatefulWidget> createState() {
    return BabyCardState(baby);
  }
}

class BabyCardState extends State<BabyCard> {
  BabyData baby;
  String renderUrl;

  BabyCardState(this.baby);

  Widget get babyCard {
    return
      new Card(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            ListTile(
              leading: const Icon(Icons.album),
              title: Text('The ${baby.name} is having:'),
              subtitle: Text('${baby.vote} Votes.'),
            ),
            new ButtonTheme.bar( // make buttons use the appropriate styles for cards
              child: new ButtonBar(
                children: <Widget>[
                  new FlatButton(
                    child: const Icon(Icons.thumb_up),
                    onPressed: () => Firestore.instance.runTransaction((transaction) async {
                       DocumentSnapshot freshSnap =
                           await transaction.get(baby.reference);
                       await transaction.update(
                           freshSnap.reference, {'vote': freshSnap['vote'] + 1});
                }),
                  ),
                  new FlatButton(
                    child: const Icon(Icons.thumbs_up_down),
                    onPressed: () { /* ... */ },
                  ),
                  new FlatButton(
                    child: const Icon(Icons.thumb_down),
                    onPressed: () { /* ... */ },
                  )]))]));
  }

  @override
  Widget build(BuildContext context) {
    return new Container(
          child:  babyCard,
        );
  }
}

Ниже показаны неправильные данные, добавляемые в карту, Dana ребенка там нет:

enter image description here

Ниже показано неправильное удаление данных с карты, Yara карта ребенка была удалена, при удалении Dana записи ребенка!:

enter image description here

Ответы [ 3 ]

0 голосов
/ 20 декабря 2018

Ниже приведено решение, показанное в кодовых метках :

import 'package:cloud_firestore/cloud_firestore.dart'; 
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {  @override  Widget build(BuildContext context) {    return MaterialApp(
     title: 'Baby Names',
     home: MyHomePage(),    );  } }

class MyHomePage extends StatefulWidget {  @override  _MyHomePageState createState() {    return _MyHomePageState();  } }

class _MyHomePageState extends State<MyHomePage> {  @override  Widget build(BuildContext context) {    return Scaffold(
     appBar: AppBar(title: Text('Baby Name Votes')),
     body: _buildBody(context),    );  }

 Widget _buildBody(BuildContext context) {    return StreamBuilder<QuerySnapshot>(
     stream: Firestore.instance.collection('baby').snapshots(),
     builder: (context, snapshot) {
       if (!snapshot.hasData) return LinearProgressIndicator();

       return _buildList(context, snapshot.data.documents);
     },    );  }

 Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {    return ListView(
     padding: const EdgeInsets.only(top: 20.0),
     children: snapshot.map((data) => _buildListItem(context, data)).toList(),    );  }

 Widget _buildListItem(BuildContext context, DocumentSnapshot data) {  final record = Record.fromSnapshot(data);

   return Padding(
     key: ValueKey(record.name),
     padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
     child: Container(
       decoration: BoxDecoration(
         border: Border.all(color: Colors.grey),
         borderRadius: BorderRadius.circular(5.0),
       ),
       child: ListTile(
         title: Text(record.name),
         trailing: Text(record.votes.toString()),
         onTap: () => Firestore.instance.runTransaction((transaction) async {
               final freshSnapshot = await transaction.get(record.reference);
               final fresh = Record.fromSnapshot(freshSnapshot);

               await transaction
                   .update(record.reference, {'votes': fresh.votes + 1});
             }),
       ),
     ),    );  } }

class Record {  final String name;  final int votes;  final DocumentReference reference;

 Record.fromMap(Map<String, dynamic> map, {this.reference})
     : assert(map['name'] != null),
       assert(map['votes'] != null),
       name = map['name'],
       votes = map['votes'];

 Record.fromSnapshot(DocumentSnapshot snapshot)
     : this.fromMap(snapshot.data, reference: snapshot.reference);

 @override  String toString() => "Record<$name:$votes>"; }
0 голосов
/ 20 декабря 2018

Точная замена моего кода:

main.dart:

import 'package:flutter/material.dart';
import 'BabyCard.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override Widget build(BuildContext context) => BabyPage();
}

class BabyPage extends StatefulWidget {
  @override State<StatefulWidget> createState() => BabyCardState();
}

BabyCard.dart:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'BabyModel.dart';

class BabyCardState extends State {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Baby Name Votes')),
      body: _buildBody(context),
    );
  }

  Widget _buildBody(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream: Firestore.instance.collection('baby').snapshots(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) return LinearProgressIndicator();

        return _buildList(context, snapshot.data.documents);
      },
    );
  }

  Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
    return ListView(
      padding: const EdgeInsets.only(top: 20.0),
      children: snapshot.map((data) => _buildListItem(context, data)).toList(),
    );
  }

  Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
    final baby = BabyData.fromSnapshot(data);

    return Padding(
      key: ValueKey(baby.name),
      padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
      child: Container(
        decoration: BoxDecoration(
          border: Border.all(color: Colors.grey),
          borderRadius: BorderRadius.circular(5.0),
        ),

        child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              ListTile(
                  leading: const Icon(Icons.album),
                  title: Text('The ${baby.name} is having:'),
                  subtitle: Text('${baby.votes} Votes.'),
                  trailing: Text(baby.votes.toString())
              ),

              new ButtonTheme.bar(
                  child: new ButtonBar(

                      children: <Widget>[
                        FlatButton(
                          child: const Icon(Icons.thumb_up),
                          onPressed: () =>
                              Firestore.instance.runTransaction((
                                  transaction) async {
                                final freshSnapshot = await transaction.get(
                                    baby.reference);
                                final fresh = BabyData.fromSnapshot(
                                    freshSnapshot);

                                await transaction
                                    .update(
                                    baby.reference, {'votes': fresh.votes + 1});
                              }),
                        ),
                        FlatButton(
                          child: const Icon(Icons.thumbs_up_down),
                          onPressed: () {
                            print(baby);
                          },
                        ),
                        FlatButton(
                          child: const Icon(Icons.thumb_down),
                          onPressed: () {
                            Firestore.instance.runTransaction((
                                transaction) async {
                              final freshSnapshot = await transaction.get(
                                  baby.reference);
                              final fresh = BabyData.fromSnapshot(
                                  freshSnapshot);

                              await transaction
                                  .update(
                                  baby.reference, {'votes': fresh.votes - 1});
                            });
                          },
                        )
                      ])
              )
            ]),
      ),
    );
  }
}

BabyModel.dart:

import 'package:cloud_firestore/cloud_firestore.dart';

class BabyData {
  final String name;
  final int votes;
  final DocumentReference reference;

  BabyData.fromMap(Map<String, dynamic> map, {this.reference}) :
          name = (map['name'] ?? 'Frank'),
          votes = (map['votes'] ?? 7);

  BabyData.fromSnapshot(DocumentSnapshot snapshot)
      : this.fromMap(snapshot.data, reference: snapshot.reference);

  // if want to use: onTap: () => print(baby),
  @override String toString() => "Record<$name:$votes>";
}

В android/app/src/gradle.build добавьте multiDexEnabled как:

android {
  defaultConfig {
    multiDexEnabled true
    }
}

ПРИМЕЧАНИЕ

Для Android убедитесь, что отображается то же имя пакетаэто: - манифест - build.gradle - .kt / .java файлы

0 голосов
/ 09 августа 2018

Вместо использования Stateful Widget в качестве ячейки, вы можете использовать обычный Widget в качестве ячейки для построителя потока.Это как-то обходное решение для ошибки, но на самом деле это может не решить вашу проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...