java - _InternalLinkedHashMap不是类型转换中自定义类的子类型。从 Firestore 中检索地图数组
问题描述
我将来自自定义类“PollOption”的数据作为地图数组存储在 Firestore 中。当我尝试检索数据时,出现此错误
_InternalLinkedHashMap<String, dynamic> is not a subtype of 'PollOption' in type cast.
我的其他数据检索正常。
我的模型被存储到一个集合中。PollOption 嵌套在此:
class Question{
//single values
final Timestamp askedOn;
final String chosenAnswer;
final String askedBy;
...
//arrays
final List<String> categories;
final List<String> declinedUsers;
final List<PollOption> pollOptions;
...
Question({
this.askedBy,
this.askedByAvatar,
this.askedByName,
...
this.pollOptions,
this.starredMessages,
...
});
我的 PollOption 模型:
class PollOption{
final String option;
final bool selected;
final int optionNumber;
final int votes;
PollOption({this.option, this.optionNumber, this.selected, this.votes});
}
我如何将数据存储到 Firestore:
Future createQuestion(Question data) async {
...
List<Map> sterilizedPolls (){
List<Map> polls = [];
if(data.pollOptions != null){
data.pollOptions.forEach((PollOption pollOption){
Map option ={
'option': pollOption.option,
'votes': pollOption.votes,
'optionNumber': pollOption.optionNumber,
'selected': pollOption.selected,
};
polls.add(option);
});
}
return polls;
}
return await questionCollection.add({
'askedBy': uid,
...
'declinedUsers': [],
'pollOptions': sterilizedPolls(),
...
});
}
我如何检索数据:
//Getting all the questions I want
Future<List<Question>> getOpenQuestions() async{
final QuerySnapshot result = await questionCollection
.where('locked', isEqualTo: false)
.where('chosenAnswer', isEqualTo: '')
.getDocuments();
final List<DocumentSnapshot> documents = result.documents;
final List<Question> openQuestions = [];
documents.forEach((data){
print('accessing database');
openQuestions.add(
Question(
question: data['question'],
)
);
});
return openQuestions;
}
//Creating list from snapshot
List<Question> _questionListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.documents.map((doc){
return Question(
askedBy: doc.data['askedBy'] ?? '',
askedByName: doc.data['askedByName'] ?? 'Anonymous',
...
pollOptions: List.from(doc.data['pollOptions']).cast<PollOption>() ?? [],
...
);
}).toList();
}
//creating stream
Stream<List<Question>> get openQuestionList {
try {
return questionCollection
.where('locked', isEqualTo: false)
.snapshots()
.map(_questionListFromSnapshot);
} catch (e) {
return e;
}
}
以及我如何显示数据:
class OpenQuestions extends StatelessWidget {
@override
Widget build(BuildContext context) {
final openQuestions = Provider.of<List<Question>>(context) ?? [];
return StreamBuilder<List<Question>>(
stream: QuestionDatabaseService().openQuestionList,
builder: (context, snapshot){
if(snapshot.hasError){
return Text('Error!');
}
if (snapshot.hasData){
return ListView.builder(
itemCount: openQuestions.length,
itemBuilder: (context, index) {
return QuestionTile(question: openQuestions[index], context: context);
},
);
}else{
return Loading();
}
}
);
//The QuestionTile Loaded
class QuestionTile extends StatelessWidget {
final Question question;
final context;
QuestionTile({this.question, this.context});
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Card(
child: ListTile(
...
title: Text(question.question),
subtitle: question.poll == false ? Text(question.message) : Text('Poll'),
onTap: (){
_showBottomModal(context, question);
},
),
),
);
}
}
//The bottom modal that pops up
void _showBottomModal(context, question)async {
showModalBottomSheet(context: context, isScrollControlled: true, builder: (context){
return Container(
//color: Color(0xFF737373),
child: Container(
child: FractionallySizedBox(
//Where the problem widget is being called
child: AnswerQuestion(question: question),
heightFactor: 0.90,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(30.0),
topRight: const Radius.circular(30.0),
)
),
),
);
});
}
//AnswerQuestion widget where the error is occurring
class _AnswerQuestionState extends State<AnswerQuestion> {
...
@override
Widget build(BuildContext context) {
return Container(
child:Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
...
Form(
key: _formKey,
child: Column(
children: [
//Where the data is being displayed with error
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 300.0
),
child: Container(
child: ListView.builder(
itemCount: widget.question.pollOptions.length,
itemBuilder: (BuildContext context, int index){
return ListTile(
title: Text(widget.question.pollOptions[index].option),
leading: Radio(
value: widget.question.pollOptions[index].optionNumber,
groupValue: _optionSelected,
onChanged: _handleRadioValueChange,
),
);
...
抱歉,如果代码太多(或不够),我仍在学习 Flutter 并希望提供尽可能多的帮助来解决此错误。
解决方案
问题出在这条线上:
pollOptions: List.from(doc.data['pollOptions']).cast<PollOption>() ?? [],
in 中的值doc.data['pollOptions']
实际上是 JSON 数据,在 dart 中表示为Map<String, dynamic>
. Dart 不知道如何自动将 Map 转换为您的对象PollOption
。
考虑一下:
pollOptions: doc.data['pollOptions'].map((Map<String, dynamic> json) => PollOption.fromJson(json)).toList()
这是假设doc.data['pollOptions']
返回一个 List 如果它是 JSON 数组则应该这样做。
当然fromJson
,您的班级需要一个工厂构造函数PollOption
:
class PollOption {
...
factory PollOption.fromJson(final Map<String, dynamic> json) {
return PollOption(json["optionkey"], etc);
}
...
}
推荐阅读
- java - 在嵌套的 for 循环中全局声明变量会在 Java 中过早地中断循环
- python - 启发式选择使点积最大化的五列数组
- python - 通过重启和关闭执行机器人任务
- sql-server - 需要说明在 SSRS 中使用的打开查询中存储过程变量是否为空
- python - 尝试在 Python 2.7 中将 SQL*Plus 输出分配给元组(二维数组)
- oauth - Keycloak 客户端与 github/gitlab/等。客户
- javascript - 如何通过正则表达式替换任何特定单词中的字符串直到字符串结尾?
- java - 如何在片段中进行内容解析?
- java - 如何将响应对象的字符串参数设置为空?
- reactjs - 如何在刷新时保存编辑的文本?