简体   繁体   中英

Migrating to null safety: The argument type 'Object?' can't be assigned to the parameter type 'List<Widget>'

After migrating to null safety I'm getting an error on ListView as "The argument type 'Object?' can't be assigned to the parameter type 'List'." I'm getting error on return ListView(children: snapshot.data,); Can anyone help me to fix this error and build a ListView for activityfeeditem in my app?

Here is my code for 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,
   ),
 ),
);
}

I have tried many ways but I counldn't figure out how I can fix this

New code for list

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

Chage your 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>[];
  }}

change you FutureBuilder as follows

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

You can also use as .

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

I see that you are using a StreamBuilder instead of FutureBuilder, but for what its worth, I believe I have found a solution to the original FutureBuilder problem.

First of all: Using the following print statements, you can troubleshoot the issue better, I found that I was Querying for paths that didnt exist with combinations of wrong.doc(userId) and.doc(ownerId) in posts.dart so the deserialization process wasn't working correctly for me when switching between users during debugging (used a provider package to remedy this eventually) but the below print statements did help me identify some issues that I had (that may or may not have contributed to the problem for you, but worth the look).

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;

Then I found that the deserialization process wasn't working correctly due to the difference between 'likes' and 'comments', due to the 'likes' having 7 inputs and 'comments' having 8 inputs. Comments have the extra 'commentData' input which I set up manually for the 'likes' in the addLikeToActivityFeed() part, and set it to an empty string as such:

'commentData': '',

Finally, I added a Dynamic type to the FutureBuilder to get rid of the => argument type 'Object?' can't be assigned to the parameter type 'List' error...

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM