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

Flutter中ListView触发Null Check Operator空值使用错误求助

Flutter ListView 触发「Null Check Operator used on a null value」错误排查方案

我用Flutter开发前端、PHP开发后端,从数据库展示数据时,ListView触发「Null Check Operator used on a null value」错误。后端接口在Postman测试能正常返回结果,我已经移除了代码中所有可能引发空检查的!运算符,也取消了列表为空的判断,但错误依然存在。相关代码如下:

class L_N_Maintenance extends StatefulWidget {
  const L_N_Maintenance({Key? key}) : super(key: key);

  @override
  _L_N_MaintenanceState createState() => _L_N_MaintenanceState();
}

class _L_N_MaintenanceState extends State<L_N_Maintenance> {
  TextEditingController emailController = TextEditingController();
  TextEditingController nameController = TextEditingController();
  TextEditingController cprController = TextEditingController();
  TextEditingController mobileController = TextEditingController();

  Future getList() async {
    SharedPreferences preferences = await SharedPreferences.getInstance();

    var useremail = preferences.getString('useremail') ?? "Not found";

    debugPrint(useremail);

    final prefs = await SharedPreferences.getInstance();
    const key = 'token';
    final value = prefs.get(key) ?? 0;

    Map<String, String> headers = {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Charset': 'utf-8',
      'Authorization': 'Bearer $value'
    };
    Map<String, dynamic> body = {
      "email": useremail,
    };
    var bodyEncoded = body.keys.map((key) => "$key=${body[key]}").join("&");
    print(bodyEncoded);
    var url = "/maintenance/owner_list.php";
    var response = await http.post(Uri.parse(ApiConstant.baseUrl + url),
        headers: headers,
        encoding: Encoding.getByName('utf-8'),
        body: bodyEncoded);
    print(response.body);
    return json.decode(response.body);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: const Color.fromARGB(255, 30, 64, 122),
        title: const Text(
          'MAINTENANCE REQUEST',
          style: TextStyle(color: Colors.orange),
        ),
        centerTitle: true,
        bottom: const PreferredSize(
            preferredSize: Size.zero,
            child: Text(
              "طلب صيانة",
              style: TextStyle(color: Colors.orange),
            )),
      ),
      body: Container(
        decoration: const BoxDecoration(
            image: DecorationImage(
          image: AssetImage("assets/building.jpg"),
          fit: BoxFit.cover,
        )),
        child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: FutureBuilder(
                future: getList(),
                builder: ((context, AsyncSnapshot snapshot) {
                  if (snapshot.hasError) print(snapshot.error);
                  if (snapshot.hasData) {
                    List list = snapshot.data as List;
                    if (list.isEmpty) {
                      return const Center(
                          child: Card(
                              color: Colors.white,
                              child: Padding(
                                padding: EdgeInsets.all(20.0),
                                child: Text('No Requests'),
                              )));
                    }
                    return ListView.builder(
                        itemCount: snapshot.data.length,
                        itemBuilder: ((context, index) {
                          return Stack(
                            children: [
                              InkWell(
                                onTap: () {
                                  Navigator.push(
                                    context,
                                    MaterialPageRoute(
                                        builder: (context) =>
                                            const L_N_MaintenanceDetails()),
                                  );
                                },
                                child: Card(
                                  color: Colors.white,
                                  shape: RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(10)),
                                  child: Padding(
                                    padding: const EdgeInsets.all(20.0),
                                    child: Row(
                                      children: [
                                        Container(
                                          width: 90,
                                          height: 70,
                                          decoration: const BoxDecoration(
                                              image: DecorationImage(
                                            image: AssetImage(
                                                "assets/building.jpg"),
                                            fit: BoxFit.cover,
                                          )),
                                        ),
                                        Padding(
                                          padding: const EdgeInsets.fromLTRB(
                                              10, 0, 0, 0),
                                          child: Column(
                                              crossAxisAlignment:
                                                  CrossAxisAlignment.start,
                                              children: [
                                                Row(
                                                  children: [
                                                    const Text(
                                                      'Problem :',
                                                      style: TextStyle(
                                                          color: Colors.grey,
                                                          fontSize: 14),
                                                    ),
                                                    Flexible(
                                                        child: Text(list[index]
                                                            ['problem']))
                                                  ],
                                                ),
                                                Row(
                                                  children: [
                                                    const Text(
                                                      'Property:',
                                                      style: TextStyle(
                                                          color: Colors.grey,
                                                          fontSize: 14),
                                                    ),
                                                    Flexible(
                                                        child: Text(list[index]
                                                            ['prop_name']))
                                                  ],
                                                ),
                                                Row(
                                                  children: [
                                                    const Text(
                                                      'Location:',
                                                      style: TextStyle(
                                                          color: Colors.grey,
                                                          fontSize: 14),
                                                    ),
                                                    Flexible(
                                                        child: Text(list[index]
                                                            ['location']))
                                                  ],
                                                ),
                                                Row(
                                                  children: [
                                                    const Text(
                                                      'Priority:',
                                                      style: TextStyle(
                                                          color: Colors.grey,
                                                          fontSize: 14),
                                                    ),
                                                    Flexible(
                                                        child: Text(list[index]
                                                            ['priority']))
                                                  ],
                                                )
                                              ]),
                                        )
                                      ],
                                    ),
                                  ),
                                ),
                              ),
                              Positioned(
                                top: 0,
                                right: 1,
                                child: Container(
                                  width: 120,
                                  height: 25,
                                  decoration: const BoxDecoration(
                                    borderRadius:
                                        BorderRadius.all(Radius.circular(2)),
                                    color: Colors.green,
                                  ),
                                  child: const Center(
                                      child: const Text(
                                    'Progress',
                                    style: const TextStyle(color: Colors.white),
                                  )),
                                ),
                              ),
                            ],
                          );
                        }));
                  } else {
                    return const Center(
                      child: CircularProgressIndicator(),
                    );
                  }
                }))),
      ),
    );
  }
}

错误排查与修复方案

1. 接口返回数据结构匹配问题

虽然Postman测试正常,但需确认后端返回的JSON是否为纯数组。如果返回的是包含数组的对象(比如{"data": [...]}),snapshot.data as List会强制类型转换失败,后续访问字段时会触发空值错误。

  • 修复:先打印response.body确认结构,若为对象则修改getList()返回逻辑:
    var decoded = json.decode(response.body);
    return decoded['data'] ?? []; // 确保返回列表,空时返回空数组
    

2. 列表字段空值处理

即使列表有数据,单个item的problem/prop_name等字段可能为null,直接传入Text组件会隐式触发空检查(Text参数不能为null)。

  • 修复:给每个字段添加空值兜底:
    Flexible(child: Text(list[index]['problem'] ?? '无'))
    Flexible(child: Text(list[index]['prop_name'] ?? '无'))
    Flexible(child: Text(list[index]['location'] ?? '无'))
    Flexible(child: Text(list[index]['priority'] ?? '无'))
    

3. FutureBuilder数据类型安全优化

代码中snapshot.data as List是强制类型转换,若snapshot.data不是List会抛出错误;同时itemCount用snapshot.data.length不如直接用list.length安全。

  • 修复:优化FutureBuilder的状态判断逻辑:
    builder: ((context, AsyncSnapshot snapshot) {
      if (snapshot.hasError) {
        print(snapshot.error);
        return Center(child: Text('加载出错: ${snapshot.error}'));
      }
      if (snapshot.connectionState == ConnectionState.waiting) {
        return const Center(child: CircularProgressIndicator());
      }
      // 安全转换为List,非List类型返回空数组
      List list = snapshot.data is List ? snapshot.data as List : [];
      if (list.isEmpty) {
        return const Center(
            child: Card(
                color: Colors.white,
                child: Padding(
                  padding: EdgeInsets.all(20.0),
                  child: Text('暂无请求'),
                )));
      }
      return ListView.builder(
          itemCount: list.length, // 改用list.length
          itemBuilder: ((context, index) {
            // ... 原有item构建代码
          }));
    })
    

4. SharedPreferences Token类型错误

final value = prefs.get(key) ?? 0;中,Token应为字符串类型,默认值设为数字0会导致Bearer $value变成Bearer 0,可能引发后端接口返回异常数据。

  • 修复:修改Token默认值为空字符串,并优化headers:
    final value = prefs.getString(key) ?? '';
    // ...
    Map<String, String> headers = {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Charset': 'utf-8',
      if (value.isNotEmpty) 'Authorization': 'Bearer $value' // 仅当Token非空时添加
    };
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 09:30:53