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

Flutter集成Firebase数据库遇空安全错误求助

解决Flutter Firebase Database的空安全错误

错误原因

你遇到的两个编译错误都是Dart空安全机制的约束导致:

"The property 'snapshot' can't be unconditionally accessed because the receiver can be 'null'."
"The method '[]' can't be unconditionally invoked because the receiver can be 'null'."

StreamBuilder返回的snapshot.data、snapshot.data.snapshot.value都可能为null,直接链式访问会触发编译检查。另外你的代码还存在键名不一致的问题(写入时键名带空格,读取时不带),会导致实际运行时读不到数据。


修复方案

  1. 显式处理空值并提取数据:在布局渲染前,先提取Firebase返回的快照数据,转为非空类型,避免重复的空判断;
  2. 统一读写的键名:将写入和读取的键名保持一致,去掉不必要的空格;
  3. 类型转换:将dynamic类型的数值转为字符串,适配Text组件的要求。

修改后的完整代码

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

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

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

class _IOTScreenState extends State<IOTScreen> {
  bool value = false;
  bool values = false;
  final dbRef = FirebaseDatabase.instance.ref();

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

  void initializeFirebase() async {
    try {
      await Firebase.initializeApp();
      print('Firebase initialized successfully');
    } catch (e) {
      print('Failed to initialize Firebase: $e');
    }
  }

  void onUpdate() {
    setState(() {
      value = !value;
    });
  }

  void onUpdate2() {
    setState(() {
      values = !values;
    });
  }

  void writeData() {
    // 统一键名,去掉末尾空格
    dbRef.child("Data").set({"Humidity:": 0, "Temperature:": 0});
    dbRef.child("LightStates").set({"switch": !value});
  }

  void writeData2() {
    dbRef.child("FanStates").set({"switch": !values});
  }

  @override
  Widget build(BuildContext context) {
    SystemChrome.setPreferredOrientations(
        [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
    return Scaffold(
      body: StreamBuilder(
        stream: dbRef.child("Data").onValue,
        builder: (context, snapshot) {
          // 先判断数据存在且无错误
          if (snapshot.hasData && !snapshot.hasError) {
            // 显式转换为非空的DatabaseEvent
            final databaseEvent = snapshot.data! as DatabaseEvent;
            // 将快照值转为Map,判断非空后再渲染
            final dataMap = databaseEvent.snapshot.value as Map<dynamic, dynamic>?;
            
            if (dataMap != null) {
              return Column(
                children: [
                  Padding(
                    padding: const EdgeInsets.all(18),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Icon(Icons.clear_all, size: 30),
                        Text(
                          "Egg Incubator",
                          style: TextStyle(
                              fontSize: 30, fontWeight: FontWeight.bold),
                        ),
                        Icon(Icons.settings, size: 30)
                      ],
                    ),
                  ),
                  SizedBox(height: 20),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Column(
                        children: [
                          Padding(
                            padding: const EdgeInsets.all(8.0),
                            child: Text(
                              "Temperature",
                              style: TextStyle(
                                  fontSize: 20, fontWeight: FontWeight.bold),
                            ),
                          ),
                          Padding(
                            padding: const EdgeInsets.all(8.0),
                            child: Text(
                              // 读取统一后的键,并转为字符串
                              dataMap["Temperature:"].toString(),
                              style: TextStyle(
                                  fontSize: 20, fontWeight: FontWeight.bold),
                            ),
                          )
                        ],
                      )
                    ],
                  ),
                  SizedBox(height: 20),
                  Column(
                    children: [
                      Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Text(
                          "Humidity",
                          style: TextStyle(
                              fontSize: 20, fontWeight: FontWeight.bold),
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Text(
                          dataMap["Humidity:"].toString(),
                          style: TextStyle(
                              fontSize: 20, fontWeight: FontWeight.bold),
                        ),
                      )
                    ],
                  ),
                  SizedBox(
                    height: 60,
                  ),
                  FloatingActionButton.extended(
                      onPressed: () {
                        writeData();
                        onUpdate();
                      },
                      label: value ? Text("Lamp ON") : Text("Lamp OFF"),
                      elevation: 20,
                      backgroundColor: value ? Colors.yellow : Colors.white60,
                      icon: value
                          ? Icon(Icons.wb_incandescent)
                          : Icon(Icons.wb_incandescent_outlined)),
                  SizedBox(
                    height: 60,
                  ),
                  FloatingActionButton.extended(
                    onPressed: () {
                      onUpdate2();
                      writeData2();
                    },
                    label: values ? Text("Fan OFF") : Text("Fan ON"),
                    elevation: 20,
                    backgroundColor:
                        values ? Colors.white60 : Colors.blueAccent,
                    icon: values
                        ? Icon(Icons.wind_power_rounded)
                        : Icon(Icons.wind_power_outlined),
                  )
                ],
              );
            }
          }
          return Container();
        },
      ),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 17:32:03