Android 颤振火基-下拉菜单项:方法';地图';被调用为空

Android 颤振火基-下拉菜单项:方法';地图';被调用为空,android,ios,firebase,flutter,dart,Android,Ios,Firebase,Flutter,Dart,在我的应用程序中,我想根据动物的种类(如果是狗或猫)展示疫苗。我遇到一个错误:对null调用了方法“map”。尝试呼叫:地图下拉菜单项。为什么会这样?我已经在方法中添加了async和await,我不明白为什么它仍然为null。下面是我的代码: 1) 在这里,我在init中调用我的DropdownContent类来准备小部件内行中的DropdownMenuItem class _VaccineDetailFormState extends State<VaccineDetailForm>

在我的应用程序中,我想根据动物的种类(如果是狗或猫)展示疫苗。我遇到一个错误:对null调用了方法“map”。尝试呼叫:地图下拉菜单项。为什么会这样?我已经在方法中添加了async和await,我不明白为什么它仍然为null。下面是我的代码:

1) 在这里,我在init中调用我的DropdownContent类来准备小部件内行中的DropdownMenuItem

class _VaccineDetailFormState extends State<VaccineDetailForm> {

final DataRepository repository = DataRepository();
String selectedVaccine = "Select";
List<String> vaccinesBySpecie;

  initState() {
    DropdownContent.getVaccines(widget.selectedPetID).then((value) => vaccinesBySpecie = value);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
    [...]
              new Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    new DropdownButton<String>(
                      value:  widget.vaccine.name == null ? selectedVaccine: widget.vaccine.name,
                      underline: Container(
                        height: 2,
                        color: Colors.grey,
                      ),
                      onChanged: (String newValue) {
                        setState(() {
                          selectedVaccine = newValue;
                          widget.vaccine.name = newValue;
                        });
                      },
                      items: vaccinesBySpecie.map<DropdownMenuItem<String>>((String value) {
                        return DropdownMenuItem<String>(
                          value: value,
                          child: Text(value),
                        );
                      }).toList(),
                    )
                  ]),

                  [...]
 Container(
                child:  FutureBuilder <List<String>>(
                    future: DropdownContent.getVaccines(widget.selectedPetID),
                    builder: (context, AsyncSnapshot snapshot) {
                      if(snapshot.data == null) {
                        return CircularProgressIndicator();
                      }
                      else {
                        return DropdownButton<String>(
                          value: widget.vaccine.name == null? selectedVaccine: widget.vaccine.name,
                          underline: Container(
                            height: 2,
                            color: Colors.grey,
                          ),
                          onChanged: (String newValue) {
                            setState(() {
                              selectedVaccine = newValue;
                              widget.vaccine.name = newValue;
                            });
                          },
                          items: snapshot.data.map<DropdownMenuItem<String>>((value) =>
                          new DropdownMenuItem<String>(
                            child: Text(value),
                            value: value,
                          ))
                              .toList(),
                        );
                      }
                    })
              )
class\u VaccineDetailFormState扩展状态{
最终数据存储库=数据存储库();
String selectedVaccine=“选择”;
列出疫苗种类;
initState(){
getVaccines(widget.selectedPetID)。然后((value)=>vaccinesBySpecie=value);
}
@凌驾
小部件构建(构建上下文){
返回脚手架(
[...]
新行(
mainAxisAlignment:mainAxisAlignment.center,
儿童:[
新下拉按钮(
值:widget.vaccine.name==null?selectedVaccine:widget.vaccine.name,
下划线:容器(
身高:2,
颜色:颜色。灰色,
),
onChanged:(字符串newValue){
设置状态(){
selectedVaccine=newValue;
widget.vaccine.name=newValue;
});
},
项目:疫苗种类图((字符串值){
返回下拉菜单项(
价值:价值,
子项:文本(值),
);
}).toList(),
)
]),
[...]
2) 下面是DropdownContent类,它在getVaccines()方法中搜索存储库以找出当前动物的物种,然后返回相应的疫苗列表

class Dropdown content

static Future<List<String>> getVaccines(String petId) async {

    final DataRepository repository = DataRepository();
    String currentSpecie = await repository.getSpecie(petId);

    if (currentSpecie.contains('Dog')) {
      return listOfVaccinesForDogs();
    }
    if (currentSpecie.contains('Cat')) {
      return listOfVaccinesForCats();
    }
}
类下拉列表内容
静态(字符串petId)异步{
最终数据存储库=数据存储库();
字符串currentSpecie=await repository.getSpecie(petId);
如果(当前种类包含('Dog')){
返回疫苗列表fordogs();
}
if(当前规格包含('Cat')){
疫苗接种者返回列表();
}
}
3) 最后是搜索动物物种的repository类

 class Repository

   Future<String> getSpecie(String petId) async {
    DocumentReference documentReference = petCollection.document(petId);
    await documentReference.get().then((snapshot) {
      return snapshot.data['specie'].toString();
    });
  }
  Future<String> getSpecie(String petId) async {
    DocumentReference documentReference = petCollection.document(petId);
    String specie;
    await documentReference.get().then((snapshot) {
      specie = snapshot.data['specie'].toString();
    });
    return specie;
  }
类存储库
未来的getSpecie(字符串petId)异步{
DocumentReference=petCollection.document(petId);
等待documentReference.get()。然后((快照){
返回snapshot.data['specie'].toString();
});
}

虽然initState方法可能是异步的,但构建方法不是。因此在调用构建方法时,vaccinesBySpecie方法为空。 解决此问题的最佳方法是初始化您的
列表vaccinesBySpecie
,就像这样
列表vaccinesBySpecie=[];
。这样,当调用构建方法时,它不会为null


作为旁注,我建议如果可以的话,使用FutureBuilder或StreamBuilder,这样你可以处理没有值(即它为空)和有值(即它不是空)的情况。

迪恩说的话启发了我的想法。我通过得出以下答案解决了这个问题:

1) 小部件内的DropdownMenuItem

class _VaccineDetailFormState extends State<VaccineDetailForm> {

final DataRepository repository = DataRepository();
String selectedVaccine = "Select";
List<String> vaccinesBySpecie;

  initState() {
    DropdownContent.getVaccines(widget.selectedPetID).then((value) => vaccinesBySpecie = value);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
    [...]
              new Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    new DropdownButton<String>(
                      value:  widget.vaccine.name == null ? selectedVaccine: widget.vaccine.name,
                      underline: Container(
                        height: 2,
                        color: Colors.grey,
                      ),
                      onChanged: (String newValue) {
                        setState(() {
                          selectedVaccine = newValue;
                          widget.vaccine.name = newValue;
                        });
                      },
                      items: vaccinesBySpecie.map<DropdownMenuItem<String>>((String value) {
                        return DropdownMenuItem<String>(
                          value: value,
                          child: Text(value),
                        );
                      }).toList(),
                    )
                  ]),

                  [...]
 Container(
                child:  FutureBuilder <List<String>>(
                    future: DropdownContent.getVaccines(widget.selectedPetID),
                    builder: (context, AsyncSnapshot snapshot) {
                      if(snapshot.data == null) {
                        return CircularProgressIndicator();
                      }
                      else {
                        return DropdownButton<String>(
                          value: widget.vaccine.name == null? selectedVaccine: widget.vaccine.name,
                          underline: Container(
                            height: 2,
                            color: Colors.grey,
                          ),
                          onChanged: (String newValue) {
                            setState(() {
                              selectedVaccine = newValue;
                              widget.vaccine.name = newValue;
                            });
                          },
                          items: snapshot.data.map<DropdownMenuItem<String>>((value) =>
                          new DropdownMenuItem<String>(
                            child: Text(value),
                            value: value,
                          ))
                              .toList(),
                        );
                      }
                    })
              )
容器(
孩子:未来建设者(
未来:DropdownContent.getVaccines(widget.selectedPetID),
生成器:(上下文,异步快照){
如果(snapshot.data==null){
返回循环ProgressIndicator();
}
否则{
返回下拉按钮(
值:widget.vaccine.name==null?selectedVaccine:widget.vaccine.name,
下划线:容器(
身高:2,
颜色:颜色。灰色,
),
onChanged:(字符串newValue){
设置状态(){
selectedVaccine=newValue;
widget.vaccine.name=newValue;
});
},
项目:snapshot.data.map((值)=>
新下拉菜单项(
子项:文本(值),
价值:价值,
))
.toList(),
);
}
})
)
2) DropdownContent类,搜索存储库以查找当前动物的物种,然后返回相应的疫苗列表:

  static Future<List<String>> getVaccines(String petId) async {
    final DataRepository repository = DataRepository();
    String currentSpecie;
    await repository.getSpecie(petId).then((value) {
      currentSpecie = value;
    });

    if (currentSpecie.contains('Dog')) {
      return listOfVaccinesForDogs();
    }
    if (currentSpecie.contains('Cat')) {
      return listOfVaccinesForCats();
    }
  }
静态(字符串petId)异步{
最终数据存储库=数据存储库();
弦电流型;
等待repository.getSpecie(petId).then((值){
当前种类=值;
});
如果(当前种类包含('Dog')){
返回疫苗列表fordogs();
}
if(当前规格包含('Cat')){
疫苗接种者返回列表();
}
}
3) 搜索动物物种的存储库类

 class Repository

   Future<String> getSpecie(String petId) async {
    DocumentReference documentReference = petCollection.document(petId);
    await documentReference.get().then((snapshot) {
      return snapshot.data['specie'].toString();
    });
  }
  Future<String> getSpecie(String petId) async {
    DocumentReference documentReference = petCollection.document(petId);
    String specie;
    await documentReference.get().then((snapshot) {
      specie = snapshot.data['specie'].toString();
    });
    return specie;
  }
Future-getSpecie(String-petId)异步{
DocumentReference=petCollection.document(petId);
弦类;
等待documentReference.get()。然后((快照){
specie=snapshot.data['specie'].toString();
});
返回物种;
}

您好。我按照您的建议进行了初始化。错误“map was called on null”已消失,但下拉列表为空,我认为这是因为您所说的FutureBuilder,所以我尝试添加此项,但现在又返回到相同的错误。