You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决Flutter报错:Null check operator used on a null value

问题根因

空检查报错和接口是否返回正确数据无关,核心是3个逻辑错误:

  • 初始化时序错误:initState是同步执行的,你在initState里生成_swipeItems、初始化_matchEngine时,异步方法getData()还没执行完成,此时_names、_images都是空列表,生成的滑动卡片列表本身就是空的;后续接口返回数据后你只往_names、_images里加了数据,没有重新生成_swipeItems和重建_matchEngine,滑动卡片组件拿不到有效数据。
  • 空检查运算符滥用:
    1. 类属性定义处直接写Auth.prefs!.getString('usrid'),如果Auth.prefs未完成初始化,这里会直接抛空错
    2. _scaffoldKey定义在MyHomePage里,但你没有给任何Scaffold绑定这个key(Scaffold在父组件CardApp中),所以_scaffoldKey.currentState永远为null,在onStackFinished回调里写_scaffoldKey.currentState!.showSnackBar必然触发空错
    3. 只判断了data != null就直接使用_matchEngine!,但首次build时_matchEngine绑定的是空的_swipeItems,组件加载时没有可渲染的卡片也会触发异常。
  • 加载逻辑判断不完整:仅判断data是否非空就渲染卡片组件,没有判断_names、_images、_swipeItems的数据是否真的准备完成。
修复步骤
  • 把Auth.prefs的取值放到initState或getData里做安全判断,不要在类属性定义时直接用强制空检查
  • 把生成_swipeItems、初始化_matchEngine的逻辑挪到getData()方法里,等接口数据全部填充到_names、_images之后再执行,执行完再调用setState刷新页面
  • 移除无效的_scaffoldKey相关逻辑,用Flutter自带的ScaffoldMessenger来弹出SnackBar,不需要依赖Scaffold的key
  • 把加载判断条件改成同时判断data、_matchEngine、_swipeItems是否有效,数据没准备完成时一直显示加载圈
修复后的核心代码
class _MyHomePageState extends State<MyHomePage> {
  String? usrId;
  dynamic data;
  String usrpic = "";

  List<SwipeItem> _swipeItems = <SwipeItem>[];
  MatchEngine? _matchEngine;
  List<String> _names = [];
  List<String> _images = [];

  getData() async{
    // 安全读取本地存储用户ID
    usrId = Auth.prefs?.getString('usrid');
    var res = await http.get(Uri.https('www.*******.net', '/mm_api/index.php',{'act':'usrlists'}));
    data = jsonDecode(res.body);
    // 先清空旧数据避免重复添加
    _names.clear();
    _images.clear();
    _swipeItems.clear();
    
    for (var i = 0; i < data.length; i++) {
      _names.add("${data[i]['fulname']}");
    }

    for (var i = 0; i < data.length; i++) {
      _images.add("${data[i]['profimage']}");
    }

    // 数据填充完成后再生成滑动卡片项
    for (int i = 0; i < _names.length; i++) {
      _swipeItems.add(SwipeItem(
        content: Content(text: _names[i], Swipeimage: _images[i]),
        likeAction: () {
          // 用ScaffoldMessenger弹提示,不需要key
          ScaffoldMessenger.of(context).showSnackBar(SnackBar(
            content: Text("Liked ${_names[i]}"),
            duration: Duration(milliseconds: 500),
          ));
        },
        nopeAction: () {
          ScaffoldMessenger.of(context).showSnackBar(SnackBar(
            content: Text("Nope ${_names[i]}"),
            duration: Duration(milliseconds: 500),
          ));
        },
        superlikeAction: () {
          ScaffoldMessenger.of(context).showSnackBar(SnackBar(
            content: Text("Superliked ${_names[i]}"),
            duration: Duration(milliseconds: 500),
          ));
        },
        onSlideUpdate: (SlideRegion? region) async {
          print("Region $region");
        }
      ));
    }
    // 卡片项生成完再初始化MatchEngine
    _matchEngine = MatchEngine(swipeItems: _swipeItems);
    print(_names);
    print(_images);
    // 所有数据准备完成再刷新页面
    setState(() {});
    print(res.body);
  }

  @override
  void initState() {
    super.initState();
    getData();
  }

  @override
  Widget build(BuildContext context) {
    final Size size = MediaQuery.of(context).size;
    final double padding = 25;
    final sidePadding = EdgeInsets.symmetric(horizontal: padding);

    return
    // 同时判断数据和组件是否初始化完成,避免强制空检查报错
      data != null && _matchEngine != null && _swipeItems.isNotEmpty? Stack(
        children: [
          NoMoreDataWidget(),
          SwipeCards(
            matchEngine: _matchEngine!,
            itemBuilder: (BuildContext context, int index) {
              return Column(
                children: [
                  Container(
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(15.0),
                      gradient: LinearGradient(
                         begin: Alignment.topRight,
                         end: Alignment.bottomLeft,
                         colors: [Colors.white, Colors.white]
                      ),
                    ),
                    width: MediaQuery.of(context).size.width,
                    child: Column(
                      children: [
                        ClipRRect(
                          borderRadius: BorderRadius.circular(15.0),
                          child:
                          Image.network(
                            "https://www.*******.net/mm_api/files/profile/"+ _images[index],
                            height: 400,
                            width: MediaQuery.of(context).size.width,
                            fit: BoxFit.cover,
                          ),
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children:[
                            Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: [
                                SizedBox(width: 5.0),
                                Text(
                                  _names[index],
                                  style: TextStyle(
                                    color: Colors.black,
                                    fontSize: 20
                                  ),
                                ),
                                addVerticalSpace(5),
                                Text(
                                  "Dieppe, Canada",
                                  style: TextStyle(
                                    color: Colors.black,
                                    fontSize: 15
                                  ),
                                )
                              ],
                            ),
                            Column(
                              crossAxisAlignment: CrossAxisAlignment.end,
                              children: [
                                InkWell(
                                  onTap: () {
                                    Navigator.push(
                                      context,
                                      MaterialPageRoute(
                                        builder: (context) => Persondetail()
                                      ),
                                    );
                                  },
                                  child: SvgPicture.asset(
                                    'assets/images/Info.svg',
                                  ),
                                ),
                              ],
                            ),
                          ]
                        ),
                      ],
                    ),
                  )
                ],
              );
            },
            onStackFinished: () {
              // 替换原来的key调用方式,避免空错
              ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                content: Text("Stack Finished"),
                duration: Duration(milliseconds: 500),
              ));
            },
            itemChanged: (SwipeItem item, int index) {
              print("item: ${item.content.text}, index: $index");
            },
            upSwipeAllowed: true,
            fillSpace: true,
          ),
        ]
      ): const Center(
        child: CircularProgressIndicator(),
      )
    ;
  }
}

额外注意:如果后续接口返回的fulname或者profimage字段可能为null,需要在添加到列表前加非空判断,避免后续渲染时出现空值问题。

内容的提问来源于stack exchange,提问作者RAF Algowid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 22:48:26