Flutter:Firebase Realtime 从对象列表中删除对象

Posted

技术标签:

【中文标题】Flutter:Firebase Realtime 从对象列表中删除对象【英文标题】:Flutter: Firebase Realtime Remove object from a list of objects 【发布时间】:2019-01-25 21:40:35 【问题描述】:

我正在咨询数据库中注册的所有俱乐部。对于每个俱乐部,我都会将其添加到对象列表中。

当人删除club时从数据库中删除club,但在item列表中没有被删除,我尝试过如下操作:

我的 NotClub-Player.dart 类

// FIREBASE CLUBS
List<Club> items = List();
Club item;
DatabaseReference itemRef;

@override
void initState() 
   super.initState();
   item = Club("","","",0,"","","","",0,0,false,"","","","","",false,"","","","","","","","","","","");
   final FirebaseDatabase database = FirebaseDatabase.instance;
   itemRef = database.reference().child(player.player_game_platform).child("CLUB");
   itemRef.onChildAdded.listen(_onEntryAdded);
   itemRef.onChildRemoved.listen(_onEntryRemoved);
   itemRef.onChildChanged.listen(_onEntryChanged);


// CLUBS LISTENERS
_onEntryAdded(Event event) 
 setState(() 
   items.add(Club.fromSnapshot(event.snapshot));
 );


_onEntryRemoved(Event event) 
 setState(() 
   items.remove(Club.fromSnapshot(event.snapshot));
 );


_onEntryChanged(Event event) 
 var old = items.singleWhere((entry) 
   return entry.key == event.snapshot.key;
 );
 setState(() 
   items[items.indexOf(old)] = Club.fromSnapshot(event.snapshot);
 );

我的问题:_onEntryRemoved 中有一个事件。在这种情况下,它会返回已删除的项目。但它不会从列表中删除相应的项目。

在数据库中,已成功删除。但是包含该对象的列表并没有删除它。

这是我的查询

rnew Flexible(
            child: new FirebaseAnimatedList(
              query: FirebaseDatabase.instance.reference().child(player.player_game_platform).child("CLUB").orderByChild("club_name"),
              itemBuilder: (BuildContext context, DataSnapshot snapshot,
                  Animation<double> animation, int index) 
                return new Column(
                  children: <Widget>[
                    new Container(
                      decoration: new BoxDecoration(
                        color: Colors.grey[300],
                      ),
                      child: new ListTile(
                        leading: new CachedNetworkImage(imageUrl: items[index].club_logo, width: 60.0),
                        title: new Text(items[index].club_name, style: new TextStyle(color: Colors.black)),
                        subtitle: new Text("CAPTAIN: "+items[index].club_captain, style: new TextStyle(color: Colors.black)),
                        trailing: new RaisedButton(
                            color: Colors.lightBlue[500],
                            child: new Text("JOIN", style: new TextStyle(color: Colors.white)),
                            onPressed: ()

                            
                        ),
                      ),
                    ),
                    new Divider(
                      color: Colors.grey[700],
                      height: 0.0,
                    ),
                  ],
                );
              ,
            ),
          ),

我在 _onEntryRemoved 中得到了什么 - 它返回正确的删除,但删除列表不适用于我。

E/flutter (15214): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter (15214): setState() called after dispose(): _join_clubState#a99f1(lifecycle state: defunct, not mounted)
E/flutter (15214): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback. The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
E/flutter (15214): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
E/flutter (15214): #0      State.setState.<anonymous closure> (package:flutter/src/widgets/framework.dart:1098:9)
E/flutter (15214): #1      State.setState (package:flutter/src/widgets/framework.dart:1124:6)
E/flutter (15214): #2      _join_clubState._onEntryRemoved (package:proclubscommunity/Club-Player.dart:807:5)
E/flutter (15214): #3      _RootZone.runUnaryGuarded (dart:async/zone.dart:1316:10)
E/flutter (15214): #4      _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:330:11)
E/flutter (15214): #5      _DelayedData.perform (dart:async/stream_impl.dart:578:14)
E/flutter (15214): #6      _StreamImplEvents.handleNext (dart:async/stream_impl.dart:694:11)
E/flutter (15214): #7      _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:654:7)
E/flutter (15214): #8      _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
E/flutter (15214): #9      _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
I/flutter (15214): club_logo: url_image, club_note: , club_since: , club_three_position: , club_market: false, club_market_color: , club_six_position: , club_premium: false, club_twitter: https://www.twitter.com/, club_first_position: , club_category: 0, club_seven_position: , club_description: , club_copa: 0, club_country: ESPAÑA, club_liga: 0, club_four_position: , club_logo_file_name: club_logo.png, club_plataform: PS4, club_nine_position: , club_captain: RaiiLKilleR, club_name: Barcelona, club_five_position: , club_eight_position: , club_id: 1, club_second_position: , club_logo_folder_name: PS4_Barcelona, club_twitch: https://www.twitch.tv/, club_youtube: https://www.youtube.com/

向小部件添加键:

            return new Column(
              key: new ObjectKey(items[index].club_name),
              children: <Widget>[
                new Container(
                  decoration: new BoxDecoration(
                    color: Colors.grey[300],
                  ),
                  child: new ListTile(
                    leading: new CachedNetworkImage(imageUrl: items[index].club_logo, width: 60.0),
                    title: new Text(items[index].club_name, style: new TextStyle(color: Colors.black)),
                    subtitle: new Text("Captain: "+items[index].club_captain, style: new TextStyle(color: Colors.black)),
                    trailing: new RaisedButton(
                        color: Colors.lightBlue[500],
                        child: new Text("JOIN", style: new TextStyle(color: Colors.white)),
                        onPressed: ()

                        
                    ),
                  ),
                ),
                new Divider(
                  color: Colors.grey[700],
                  height: 0.0,
                ),
              ],
            );

_onEntryRemoved()

  _onEntryRemoved(Event event) 
    setState(() 
      print(event.snapshot.value['club_name']);
      items.remove(event.snapshot.value['club_name']);
    );
  

【问题讨论】:

打印哪个 event.snapshot 在 _onEntryRemoved 上返回 我已经用 _onEntryRemoved 中的内容更新了帖子 ***.com/questions/50080860/… 我添加了密钥,但我仍然遇到同样的问题。我已经更新了帖子,以防我做错了。谢谢 【参考方案1】:

你的问题在于Club

当您创建List&lt;Club&gt; items 并稍后执行items.remove(clubInstance) 时,remove 方法在内部将使用标准对象 equals 方法实现,它不知道您的密钥。

如果您尝试使用items.indexOf(clubInstance),也会发生同样的情况。它永远不会“找到”该项目,总是返回-1

您可以更改您的实现,遍历项目以找出您需要删除的确切项目,然后将其删除,或者您可以在 Club 类中实现 ==hashCode

如果你打算使用club_name作为key,添加这两行可能会解决它。

class Club 
  Club(this.club_name);
  final String club_name;

  // this is what you would have to add to your class:
  bool operator ==(o) => o is Club && o.club_name == club_name;
  int get hashCode => club_name.hashCode;

注意:这与颤振或火力无关,这只是飞镖!

【讨论】:

以上是关于Flutter:Firebase Realtime 从对象列表中删除对象的主要内容,如果未能解决你的问题,请参考以下文章

带有一个适用于android、ios、web的插件的flutter firebase(实时)数据库? [复制]

如何在 swift 4.0 中获取 firebase-realtime-database 中的特定值

从 firebase-realtime-database 过滤数据

在 Firebase-Realtime Database 上使用啥规则让用户注册和登录?

如何从 Firebase Realtime DB 读取孩子的值?

如何使用 Firebase RealTime 数据库根据特定类别获取项目集合