Rog*_*rto 2 dart firebase flutter google-cloud-firestore
我使用 Flutter 构建了一个网络应用程序。几个月前构建和部署没有任何问题。今天跳回代码,没有更新任何代码,现在收到以下错误:
\n Error:Expected a value of type 'List<String>', but got one of type 'List<dynamic>'\n\xe2\x95\x90\xe2\x95\x90\xe2\x95\xa1 EXCEPTION CAUGHT BY WIDGETS LIBRARY \xe2\x95\x9e\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\nThe following JSNoSuchMethodError was thrown building NewHomeScreen(dirty, dependencies:\n[_EffectiveTickerMode, _InheritedProviderScope<List<ContentModel>>, MediaQuery], state:\n_NewHomeScreenState#295f1(tickers: tracking 2 tickers)):\nNoSuchMethodError: invalid member on null: 'length'\nRun Code Online (Sandbox Code Playgroud)\n这是我从 Firebase 获取数据的位置和方式:
\nvoid main() => runApp(MyApp());\n\nclass MyApp extends StatefulWidget {\n // This widget is the root of your application.\n @override\n _MyAppState createState() => _MyAppState();\n}\n\n@override\nvoid initState() {}\n\nclass _MyAppState extends State<MyApp> {\n\n @override\n Widget build(BuildContext context) {\n final linksCollection = Firestore.instance.collection('links');\n final contentCollection = Firestore.instance.collection('content');\n\n final contentObjects = contentCollection.snapshots().map((snapshot) {\n return snapshot.documents\n .map((doc) => ContentModel.fromDocument(doc))\n .toList();\n });\n\n return MultiProvider(\n providers: [\n StreamProvider<List<ContentModel>>(\n create: (_) => contentObjects,\n initialData: [],\n catchError: (BuildContext context, e) {\n print("Error:$e");\n return null;\n },\n ),\n\n Provider<CollectionReference>(create: (_) => linksCollection),\n\n ],\n child: MaterialApp(\n title: 'My App',\n debugShowCheckedModeBanner: false,\n theme: ThemeData(primarySwatch: Colors.blue, fontFamily: 'IBM_Plex'),\n initialRoute: '/',\n routes: {'/': (context) => NewHomeScreen()},\n ),\n );\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n然后,我通过使用 Provider 访问该数据,在整个应用程序中使用这些数据,如下所示:
\nclass NewHomeScreen extends StatefulWidget {\n @override\n _NewHomeScreenState createState() => _NewHomeScreenState();\n}\n\nclass _NewHomeScreenState extends State<NewHomeScreen>\n with TickerProviderStateMixin {\n\n @override\n void initState() {\n super.initState();\n\n }\n\n @override\n Widget build(BuildContext context) {\n final contentObjects = Provider.of<List<ContentModel>>(context);\n\n List<ContentModel> expertList = [];\n\n for (var data in contentObjects) {\n if(data.topic == 'expert') {\n expertList.add(data);\n }\n }\n\n return Scaffold(\n body: CustomScrollView(\n slivers: <Widget>[\n SliverAppBar(\n leading: Container(\n child: Padding(\n padding: EdgeInsets.only(left: 10.0),\n child: GestureDetector(\n onTap: () {\n Navigator.push(\n context,\n MaterialPageRoute(\n builder: (context) => NewHomeScreen(),\n ),\n );\n },\n \n ),\n )\n\n ),\n backgroundColor: appBarColor,\n expandedHeight: 50.0,\n pinned: true,\n flexibleSpace: FlexibleSpaceBar(\n title: Align(\n alignment: Alignment.center,\n ),\n centerTitle: true,\n\n stretchModes: [\n StretchMode.blurBackground,\n StretchMode.zoomBackground\n ],\n background: Image.network(\n 'https://www.image.com',\n fit: BoxFit.cover,\n ),\n ),\n actions: <Widget>[\n InkResponse(\n onTap: () {\n Navigator.push(\n context,\n SlideRightRoute(\n page: SearchScreen(),\n ),\n );\n },\n child: new Padding(\n padding: const EdgeInsets.all(12.0),\n child: Icon(\n Icons.search,\n size: 26.0,\n color: Colors.white,\n ),\n ),\n ),\n ],\n ),\n SliverToBoxAdapter(\n child: Column(\n children: <Widget>[\n FadeIn(1.00, Center(child: HeaderWidget())),\n FadeIn(2.33, Center(child: HashtagRow())),\n SizedBox(\n height: 20,\n ),\n SizedBox(height: 50),\n FadeIn(\n 2.66,\n SectionContainer(\n sectionTitle: "Expertise in focus",\n child: Padding(\n padding: EdgeInsets.only(top: 13, bottom: 13),\n child: Container(\n height: 450,\n child: ListView.builder(\n padding: EdgeInsets.only(left: 50, right: 50),\n scrollDirection: Axis.horizontal,\n itemCount: expertList.length,\n itemBuilder: (ctx, index) {\n return GestureDetector(\n onTap: () {\n Navigator.push(\n context,\n MaterialPageRoute(\n builder: (context) => ExpertDetailsScreen(\n contentModel: expertList[index],\n ),\n ),\n );\n },\n child: Column(\n children: <Widget>[\n Padding(\n padding: EdgeInsets.only(\n left: 15.0,\n right: 15.0,\n ),\n child: Hero(\n tag: expertList[index].title.toString(),\n child: Align(\n alignment: Alignment.centerLeft,\n child: CircleAvatar(\n radius: 150.0,\n backgroundImage: NetworkImage(\n expertList[index].imglink),\n backgroundColor: Colors.transparent,\n ),\n ),\n ),\n ),\n Container(\n decoration: BoxDecoration(\n borderRadius: BorderRadius.circular(8.0),\n\n ),\n child: Padding(\n padding: const EdgeInsets.all(10),\n child: Center(\n child: Text(\n expertList[index].tags[1],\n textAlign: TextAlign.center,\n style: forumNameTextStyleTwo,\n ),\n ),\n ),\n ),\n SizedBox(height: 3),\n Text(\n expertList[index].title,\n textAlign: TextAlign.center,\n style: labelTextStyle,\n ),\n ],\n ),\n );\n },\n ),\n ),\n ),\n ),\n ),\n SizedBox(height: 50)\n ],\n ),\n )\n ],\n ),\n floatingActionButton: FloatingActionButton.extended(\n onPressed: () {\n Navigator.push(\n context,\n ScaleRoute(\n page: AddResource(),\n ),\n );\n },\n label: Text('Suggest a resource'),\n icon: Icon(Icons.add),\n backgroundColor: myColor,\n ),\n\n );\n }\n\n void htmlOpenLink(String s) {\n html.window.open(s, '_blank');\n }\n}\n\nclass SlideRightRoute extends PageRouteBuilder {\n final Widget page;\n SlideRightRoute({this.page})\n : super(\n pageBuilder: (\n BuildContext context,\n Animation<double> animation,\n Animation<double> secondaryAnimation,\n ) =>\n page,\n transitionsBuilder: (\n BuildContext context,\n Animation<double> animation,\n Animation<double> secondaryAnimation,\n Widget child,\n ) =>\n SlideTransition(\n position: Tween<Offset>(\n begin: const Offset(-1, 0),\n end: Offset.zero,\n ).animate(\n CurvedAnimation(\n parent: animation,\n curve: Curves.fastOutSlowIn,\n ),\n ),\n child: child,\n ),\n );\n}\n\nclass ScaleRoute extends PageRouteBuilder {\n final Widget page;\n ScaleRoute({this.page})\n : super(\n pageBuilder: (\n BuildContext context,\n Animation<double> animation,\n Animation<double> secondaryAnimation,\n ) =>\n page,\n transitionsBuilder: (\n BuildContext context,\n Animation<double> animation,\n Animation<double> secondaryAnimation,\n Widget child,\n ) =>\n ScaleTransition(\n scale: Tween<double>(\n begin: 0.0,\n end: 1.0,\n ).animate(\n CurvedAnimation(\n parent: animation,\n curve: Curves.fastOutSlowIn,\n ),\n ),\n child: child,\n ),\n );\n}\n\nclass MyCustomClipper extends CustomClipper<Path> {\n final double distanceFromWall = 12;\n final double controlPointDistanceFromWall = 2;\n\n @override\n Path getClip(Size size) {\n final double height = size.height;\n final double halfHeight = size.height * 0.5;\n final double width = size.width;\n\n Path clippedPath = Path();\n clippedPath.moveTo(0, halfHeight);\n clippedPath.lineTo(0, height - distanceFromWall);\n clippedPath.quadraticBezierTo(0 + controlPointDistanceFromWall,\n height - controlPointDistanceFromWall, 0 + distanceFromWall, height);\n clippedPath.lineTo(width, height);\n clippedPath.lineTo(width, 0 + 30.0);\n clippedPath.quadraticBezierTo(width - 5, 0 + 5.0, width - 35, 0 + 15.0);\n clippedPath.close();\n return clippedPath;\n }\n\n @override\n bool shouldReclip(CustomClipper<Path> oldClipper) {\n return true;\n }\n}\n\nclass CustomShapeBorder extends ShapeBorder {\n final double distanceFromWall = 12;\n final double controlPointDistanceFromWall = 2;\n\n @override\n EdgeInsetsGeometry get dimensions => null;\n\n @override\n Path getInnerPath(Rect rect, {TextDirection textDirection}) {\n return null;\n }\n\n @override\n Path getOuterPath(Rect rect, {TextDirection textDirection}) {\n return getClip(Size(220.0, 70.0));\n }\n\n @override\n void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {}\n\n @override\n ShapeBorder scale(double t) {\n return null;\n }\n\n Path getClip(Size size) {\n Path clippedPath = Path();\n clippedPath.moveTo(0 + distanceFromWall, 0);\n clippedPath.quadraticBezierTo(0 + controlPointDistanceFromWall,\n 0 + controlPointDistanceFromWall, 0, 0 + distanceFromWall);\n clippedPath.lineTo(0, size.height - distanceFromWall);\n clippedPath.quadraticBezierTo(\n 0 + controlPointDistanceFromWall,\n size.height - controlPointDistanceFromWall,\n 0 + distanceFromWall,\n size.height);\n clippedPath.lineTo(size.width - distanceFromWall, size.height);\n clippedPath.quadraticBezierTo(\n size.width - controlPointDistanceFromWall,\n size.height - controlPointDistanceFromWall,\n size.width,\n size.height - distanceFromWall);\n clippedPath.lineTo(size.width, size.height * 0.6);\n clippedPath.quadraticBezierTo(\n size.width - 1,\n size.height * 0.6 - distanceFromWall,\n size.width - distanceFromWall,\n size.height * 0.6 - distanceFromWall - 3);\n clippedPath.lineTo(0 + distanceFromWall + 6, 0);\n clippedPath.close();\n return clippedPath;\n }\n\n}\nRun Code Online (Sandbox Code Playgroud)\n这是数据的模型类:
\nclass ContentModel {\n String title;\n String description;\n String imglink;\n int contentId;\n List<String> tags;\n List<String> focusAreas;\n int likeCount;\n String myIcon;\n bool isNew;\n String content;\n String contentLink;\n String appColor;\n double positionVar;\n String detailScreenLink;\n String documentId;\n String topic;\n String hashtag;\n\n ContentModel(\n {this.title,\n this.description,\n this.imglink,\n this.contentId,\n this.tags,\n this.likeCount,\n this.myIcon,\n this.isNew,\n this.content,\n this.contentLink,\n this.appColor,\n this.positionVar,\n this.detailScreenLink,\n this.documentId,\n this.topic,\n this.focusAreas,\n this.hashtag});\n\n Map<String, dynamic> toMap() {\n return {\n 'title': title,\n 'description': description,\n 'imglink': imglink,\n 'contentId': contentId,\n 'tags': tags,\n 'likeCount': likeCount,\n 'isNew': isNew,\n 'content': content,\n 'contentLink': contentLink,\n 'appColor': appColor,\n 'positionVar': positionVar,\n 'detailScreenLink': detailScreenLink,\n 'documentId': documentId,\n 'topic': topic,\n 'focusAreas': focusAreas,\n 'hashtag': hashtag\n };\n }\n\n static ContentModel fromDocument(DocumentSnapshot document) {\n if (document == null || document.data == null) return null;\n\n return ContentModel(\n documentId: document.documentID,\n imglink: document.data['imglink'],\n title: document.data['title'],\n description: document.data['description'],\n likeCount: document.data['likeCount'],\n tags: document.data['tags'],\n isNew: document.data['isNew'],\n content: document.data['content'],\n contentLink: document.data['contentLink'],\n appColor: document.data['appColor'],\n positionVar: document.data['positionVar'],\n detailScreenLink: document.data['detailScreenLink'],\n topic: document.data['topic'],\n focusAreas: document.data['focusAreas'],\n hashtag: document.data['hashtag']);\n }\n\n Map toJson() => {\n 'title': title,\n 'description': description,\n 'imglink': imglink,\n 'contentId': contentId,\n 'tags': tags,\n 'likeCount': likeCount,\n 'isNew': isNew,\n 'content': content,\n 'contentLink': contentLink,\n 'appColor': appColor,\n 'positionVar': positionVar,\n 'detailScreenLink': detailScreenLink,\n 'documentId': documentId,\n 'topic': topic,\n 'focusAreas': focusAreas,\n 'hashtag': hashtag\n };\n}\nRun Code Online (Sandbox Code Playgroud)\n
给定
List<dynamic> dynamicList;
Run Code Online (Sandbox Code Playgroud)
您可以使用
var stringList = List<String>.from(dlist);
Run Code Online (Sandbox Code Playgroud)
将 a 转换List<dynamic>为List<String>
因此你需要修复你的模式:
static ContentModel fromDocument(DocumentSnapshot document) {
if (document == null || document.data == null) return null;
return ContentModel(
documentId: document.documentID,
imglink: document.data['imglink'],
title: document.data['title'],
description: document.data['description'],
likeCount: document.data['likeCount'],
tags: List<String>.from(document.data['tags']),// to convert a List<dynamic> to List<String>
isNew: document.data['isNew'],
content: document.data['content'],
contentLink: document.data['contentLink'],
appColor: document.data['appColor'],
positionVar: document.data['positionVar'],
detailScreenLink: document.data['detailScreenLink'],
topic: document.data['topic'],
focusAreas: List<String>.from(document.data['focusAreas']), //to convert a List<dynamic> to List<String>
hashtag: document.data['hashtag']);}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
871 次 |
| 最近记录: |