【问题标题】:Migrating to null safety: The argument type 'Object?' can't be assigned to the parameter type 'List<Widget>'迁移到空安全:参数类型“对象?”不能分配给参数类型“List<Widget>”
【发布时间】:2021-08-29 10:03:39
【问题描述】:

迁移到空安全后,我在 ListView 上收到错误消息,显示为“参数类型 'Object?'不能分配给参数类型“列表”。” 我在return ListView(children: snapshot.data,); 上遇到错误 谁能帮我解决这个错误并在我的应用中为 activityfeeditem 构建一个 ListView?

这是我的 activity_feed.dart 代码,

class ActivityFeed extends StatefulWidget {
@override
_ActivityFeedState createState() => _ActivityFeedState();
}

class _ActivityFeedState extends State<ActivityFeed> {

getActivityFeed() async {
 QuerySnapshot snapshot = await activityFeedRef
     .doc(currentUser!.id)
     .collection('feedItems')
     .orderBy('timestamp', descending: true)
     .limit(50)
     .get();
 List<ActivityFeedItem> feedItems = [];
 snapshot.docs.forEach((doc) {
   feedItems.add(ActivityFeedItem.fromDocument(doc));
   print('Activity Feed Item: ${doc.data}');
 });

 return feedItems;
}

@override
Widget build(BuildContext context) {
 return Scaffold(
   backgroundColor: Colors.deepPurple[50],
   appBar: header(context, titleText: "Activity Feed"),
   body: Container(
     child: FutureBuilder(
       future: getActivityFeed(),
       builder: (context, snapshot) {
         if (!snapshot.hasData) {
           return circularProgress();
         }
         return ListView(
           children: snapshot.data,

// Here I'm getting error on `snapshot.data`

         );
       },
     ),
   ),
 );
}
}

Widget? mediaPreview;
String? activityItemText;

class ActivityFeedItem extends StatelessWidget {
final String? username;
final String? userId;
final String? type; // 'like', 'follow', 'comment'
final String? mediaUrl;
final String? postId;
final String? userProfileImg;
final String? commentData;
final Timestamp? timestamp;

ActivityFeedItem({
 this.username,
 this.userId,
 this.type,
 this.mediaUrl,
 this.postId,
 this.userProfileImg,
 this.commentData,
 this.timestamp,
});

factory ActivityFeedItem.fromDocument(DocumentSnapshot doc) {
 return ActivityFeedItem(
   username: doc['username'],
   userId: doc['userId'],
   type: doc['type'],
   postId: doc['postId'],
   userProfileImg: doc['userProfileImg'],
   commentData: doc['commentData'],
   timestamp: doc['timestamp'],
   mediaUrl: doc['mediaUrl'],
 );
}

showPost(context) {
 Navigator.push(
     context,
     MaterialPageRoute(
         builder: (context) => PostScreen(postId: postId, userId: userId)));
}

configureMediaPreview(context) {
 if (type == "like" || type == 'comment') {
   mediaPreview = GestureDetector(
     onTap: () => showPost(context),
     child: Container(
       height: 50.0,
       width: 50.0,
       child: AspectRatio(
           aspectRatio: 16 / 9,
           child: Container(
             decoration: BoxDecoration(
               image: DecorationImage(
                 fit: BoxFit.cover,
                 image: CachedNetworkImageProvider(mediaUrl!),
               ),
             ),
           )),
     ),
   );
 } else {
   mediaPreview = Text('');
 }

 if (type == 'like') {
   activityItemText = "liked your post";
 } else if (type == 'follow') {
   activityItemText = "is following you";
 } else if (type == 'comment') {
   activityItemText = 'replied: $commentData';
 } else {
   activityItemText = "Error: Unknown type '$type'";
 }
}

@override
Widget build(BuildContext context) {
 configureMediaPreview(context);

 return Padding(
   padding: EdgeInsets.only(bottom: 2.0),
   child: Container(
     color: Colors.white54,
     child: ListTile(
       title: GestureDetector(
         onTap: () => showProfile(context, profileId: userId),
         child: RichText(
           overflow: TextOverflow.ellipsis,
           text: TextSpan(
               style: TextStyle(
                 fontSize: 14.0,
                 color: Colors.black,
               ),
               children: [
                 TextSpan(
                   text: username,
                   style: TextStyle(fontWeight: FontWeight.bold),
                 ),
                 TextSpan(
                   text: ' $activityItemText',
                 ),
               ]),
         ),
       ),
       leading: CircleAvatar(
         backgroundImage: CachedNetworkImageProvider(userProfileImg!),
       ),
       subtitle: Text(
         timeago.format(timestamp!.toDate()),
         overflow: TextOverflow.ellipsis,
       ),
       trailing: mediaPreview,
     ),
   ),
 );
}
}

showProfile(BuildContext context, {String? profileId}) {
Navigator.push(
 context,
 MaterialPageRoute(
   builder: (context) => Profile(
     profileId: profileId,
   ),
 ),
);
}

我尝试了很多方法,但我无法弄清楚如何解决这个问题

列表的新代码

Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Colors.deepPurple[50],
        appBar: header(context, titleText: "Activity Feed"),
        body: Container(
          child: StreamBuilder<QuerySnapshot>(
              stream: activityFeedRef
                  .doc(currentUser!.id)
                  .collection('feedItems')
                  .orderBy('timestamp', descending: true)
                  .limit(50)
                  .snapshots(),
              builder: (context, snapshot) {
                if (!snapshot.hasData) {
                  return Center(
                    child: circularProgress(),
                  );
                } else
                  return ListView(
                    children: snapshot.data!.docs.map((doc) {
                      return Card(
                        child: ListTile(
                          title: GestureDetector(
                            onTap: () =>
                                showProfile(context, profileId: doc['userId']),
                            child: RichText(
                              overflow: TextOverflow.ellipsis,
                              text: TextSpan(
                                  style: TextStyle(
                                    fontSize: 14.0,
                                    color: Colors.black,
                                  ),
                                  children: [
                                    TextSpan(
                                      text: doc['username'],
                                      style: TextStyle(
                                          fontWeight: FontWeight.bold),
                                    ),
                                    TextSpan(
                                      text: ' $activityItemText',
                                    ),
                                  ]),
                            ),
                          ),
                          leading: CircleAvatar(
                            backgroundImage: CachedNetworkImageProvider(
                                doc['userProfileImg']!),
                          ),
                          subtitle: Text(
                            timeago.format(doc['timestamp']!.toDate()),
                            overflow: TextOverflow.ellipsis,
                          ),
                          trailing: mediaPreview,
                        ),
                      );
                    }).toList(),
                  );
              }),
        ));
  }

【问题讨论】:

    标签: flutter flutter-listview flutter-futurebuilder dart-null-safety


    【解决方案1】:

    更改您的getActivityFeed

     Future<List<ActivityFeedItem>>   getActivityFeed() async {
     try{
       QuerySnapshot snapshot = await activityFeedRef
         .doc(currentUser!.id)
         .collection('feedItems')
         .orderBy('timestamp', descending: true)
         .limit(50)
         .get();
     List<ActivityFeedItem> feedItems = [];
     snapshot.docs.forEach((doc) {
       feedItems.add(ActivityFeedItem.fromDocument(doc));
       print('Activity Feed Item: ${doc.data}');
     });
    
     return feedItems;
    }
    
    catch (error) {
       print(error);
       return <ActivityFeedItem>[];
      }}
    

    如下更改你FutureBuilder

    FutureBuilder<List<ActivityFeedItem>>(
           future: getActivityFeed(),
           builder: (BuildContextcontext, AsyncSnapshot<List<ActivityFeedItem>> snapshot) {
             if (snapshot.hasError){
              return Center(child: Text("You have an error in loading 
              data"));   
              }
             if (snapshot.hasData) {
               return ListView(
               children: snapshot.data!,
             );
             }
             return CirclularProgressIndicator();
    

    【讨论】:

    • 参数类型为“List?”时出现错误不能分配给参数类型“List”。
    • 谢谢,但它仍然无法正常工作,即使它在我运行应用程序时没有显示错误,该页面一直显示循环进度并且没有加载任何项目,在调试控制台上它显示为 Activity Feed Item: Closure: ( ) => Map from Function 'data':.
    • snapsot.hasData 为真时,您确定要返回ListView
    • @MaldivesHunt 你能在if (snapshot.hasData) 之前添加print(snapshot.data) 以查看打印的内容吗?
    • 这意味着您的 getActivityFeed() 函数要么返回 null 要么抛出错误(很可能)。 “Activity Feed Item: ...”会打印在您的控制台中吗?
    【解决方案2】:

    您也可以使用as

    ListView(
      children: object as List<Widget>,
    )
    

    【讨论】:

      【解决方案3】:

      我看到您使用的是 StreamBuilder 而不是 FutureBuilder,但就其价值而言,我相信我已经找到了解决原始 FutureBuilder 问题的方法。

      首先:使用以下打印语句,您可以更好地解决问题,我发现我正在查询posts.dart中错误.doc(userId)和.doc(ownerId)组合不存在的路径因此,在调试期间在用户之间切换时,反序列化过程对我来说无法正常工作(最终使用提供程序包来解决这个问题)但下面的打印语句确实帮助我确定了我遇到的一些问题(可能会或可能不会促成你的问题,但值得一看)。

      getActivityFeed() async {
      QuerySnapshot snapshot = await FirebaseFirestore.instance
          .collection('feed')
          .doc(_auth.currentUser!.uid)
          .collection('feedItems')
          .orderBy('timestamp', descending: true)
          .limit(50)
          .get();
      
      List<ActivityFeedItem> feedItems = [];
      snapshot.docs.forEach((doc) {
        feedItems.add(ActivityFeedItem.fromDocument(doc));
        print('Activity Feed Item: ${doc.id}');
        print('Activity Feed Item: ${doc.data()}');
      });
      
      // return feedItems;
      return snapshot.docs;
      

      然后我发现由于“likes”和“cmets”之间的差异,反序列化过程无法正常工作,因为“likes”有 7 个输入,而“cmets”有 8 个输入。评论有额外的“commentData”输入,我在 addLikeToActivityFeed() 部分中为“喜欢”手动设置,并将其设置为空字符串:

      'commentData': '',
      

      最后,我在 FutureBuilder 中添加了一个 Dynamic 类型,以摆脱 => 参数类型 'Object?'无法分配给参数类型'List'错误...

      Container(
                  child: FutureBuilder<dynamic>(
                    future: getActivityFeed(),
                    builder: (context, snapshot) {
                      if (!snapshot.hasData) {
                        return circularProgress();
                      }
                      return ListView(
                        children: snapshot.data,
                      );
                    },
                  ),
                ),
      

      【讨论】:

        猜你喜欢
        • 2021-07-04
        • 2021-10-24
        • 2021-08-05
        • 2021-09-13
        • 1970-01-01
        • 2021-11-06
        • 2021-08-29
        • 2019-12-06
        • 2021-08-23
        相关资源
        最近更新 更多