我将来自自定义类“PollOption”的数据存储在Firestore中作为 map 数组。当我尝试检索数据时,出现此错误_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>() ?? [],
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);
}
...
}