java - _InternalLinkedHashMap<String,dynamic> 不是类型转换中自定义类的子类型。从 Firestore 检索 map 数组

标签 java flutter dart google-cloud-firestore

我将来自自定义类“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']返回一个列表,如果它是 JSON 数组,则应该这样做。

当然你需要一个fromJson您的工厂构造函数 PollOption类:

class PollOption {
...
   factory PollOption.fromJson(final Map<String, dynamic> json) {
      return PollOption(json["optionkey"], etc);
   }
...
}

关于java - _InternalLinkedHashMap<String,dynamic> 不是类型转换中自定义类的子类型。从 Firestore 检索 map 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60367869/

相关文章:

java - 为什么 gradlew build 命令不能仅编译和构建已更改的内容并使过程更快?

flutter - Flutter_bloc中RepositoryProvider的实际使用

json - 如何在Flutter ListView构建期间测试json属性是否存在

flutter - ListView 中的Flutter组合框项目

java - 如何只获取 java.sql.ResultSet 的第一行?

java - 使用集合对员工姓名列表进行排序

flutter - 错误 :flutter/lib/ui/ui_dart_state. cc(199) 未处理的异常:对空值使用空检查运算符

firebase - flutter: 'String'类型不是 'List<dynamic>'类型的子类型

firebase - 如何在不带X的Flutter中为iOS添加Firebase SDK-代码

Java 组件在 GridBagLayout 上的定位