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

Flutter Sqflite切换登录状态页面时触发空值运算符错误

问题描述

尝试根据用户登录状态在登录页和首页之间切换,替换首页为其他页面时逻辑正常,热重启后能正确展示对应页面;但切回首页时,会触发“null operator used on null value”错误。

相关代码

页面切换逻辑(Testing组件)

class Testing extends StatefulWidget {
  const Testing({super.key});

  @override
  State<Testing> createState() => _TestingState();
}

class _TestingState extends State<Testing> {
  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: TodoServiceHelper().checkifLoggedIn(),
      builder: ((context, snapshot) {
        if (!snapshot.hasData) {
          return Container(
            child: Center(
              child: CircularProgressIndicator(),
            ),
          );
        }
        if (snapshot.hasError) {
          print(snapshot.hasError);
          return Container(
            child: Center(
              child: CircularProgressIndicator(),
            ),
          );
        }
        if (snapshot.data!.isNotEmpty) {
          print(snapshot.data);
          return RegisterPage();
          // 返回HomePage时会触发null check错误
        } else
          return Login();
      }),
    );
  }
}

首页(HomePage组件)

class HomePage extends StatefulWidget {
  String? username;
  HomePage({this.username});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final GlobalKey<FormState> formKey = GlobalKey();
  TextEditingController termController = TextEditingController();
  void clearText() {
    termController.clear();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: <Widget>[
          IconButton(
            onPressed: () {
              User loginUser =
                  User(username: widget.username.toString(), isLoggedIn: false);
              TodoServiceHelper().updateUserName(loginUser);
              Navigator.pushReplacement(
                  context,
                  MaterialPageRoute(
                      builder: (BuildContext context) => Login()));
            },
            icon: Icon(Icons.logout),
            color: Colors.white,
          )
        ],
        title: FutureBuilder(
            future: TodoServiceHelper().getTheUser(widget.username!),
            builder: (context, snapshot) {
              if (!snapshot.hasData) {
                return Container(
                  child: Center(
                    child: CircularProgressIndicator(),
                  ),
                );
              }
              return Text(
                'Welcome ${snapshot.data!.username}',
                style: TextStyle(color: Colors.white),
              );
            }),
      ),
      body: SingleChildScrollView(
        child: Column(children: [
          Column(
            children: [
              Padding(
                padding: const EdgeInsets.all(12.0),
                child: Form(
                  key: formKey,
                  child: Column(
                    children: <Widget>[
                      TextFormField(
                        controller: termController,
                        decoration: InputDecoration(
                          filled: true,
                          fillColor: Colors.white,
                          enabledBorder: OutlineInputBorder(),
                          labelText: 'search todos',
                        ),
                      ),
                      TextButton(
                          onPressed: () async {
                            await Navigator.push(
                              context,
                              MaterialPageRoute(
                                  builder: (context) => ShowingSerachedTitle(
                                        userNamee: widget.username!,
                                        searchTerm: termController.text,
                                      )),
                            );

                            print(termController.text);
                            clearText();
                            setState(() {});
                          },
                          child: Text(
                            'Search',
                          )),
                      Divider(
                        thickness: 3,
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
          Container(
            child: Stack(children: [
              Positioned(
                bottom: 0,
                child: Text(
                  ' done Todos',
                  style: TextStyle(fontSize: 12),
                ),
              ),
              IconButton(
              
                onPressed: () async {
                  await Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) =>
                            CheckingStuff(userNamee: widget.username!)),
                  );
                  setState(() {});
                },
                icon: Icon(Icons.filter),
              ),
            ]),
          ),
          Divider(
            thickness: 3,
          ),
          Container(
            child: TodoListWidget(name: widget.username!),
            height: 1000,
            width: 380,
          )
        ]),
      ),
      floatingActionButton: FloatingActionButton(
        backgroundColor: Color.fromARGB(255, 255, 132, 0),
      
        onPressed: () async {
          await showDialog(
            barrierDismissible: false,
            context: context,
            builder: ((context) {
              return AddNewTodoDialogue(name: widget.username!);
            }),
          );
          setState(() {});
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

登录状态检查函数

Future<List<User>> checkifLoggedIn() async {
  final Database db = await initializeDB();
  final List<Map<String, Object?>> result = await db.query(
    'users',
    where: 'isLoggedIn = ?',
    whereArgs: ['1'],
  );
  List<User> filtered = [];
  for (var item in result) {
    filtered.add(User.fromMap(item));
  }
  return filtered;
}
问题原因

错误根源是返回HomePage时没有传入username参数,而HomePage内部大量使用widget.username!这个非空断言——当username为null时,非空断言就会触发"null operator used on null value"错误。

当前返回RegisterPage时能正常运行,是因为RegisterPage没有依赖这个必填的username;但HomePage的所有核心逻辑(获取用户信息、跳转搜索页、待办列表等)都依赖widget.username,且直接用了非空断言强制解包。

修复方案

修改Testing组件中返回HomePage的代码,从登录用户列表里取出第一个用户的username传入:

if (snapshot.data!.isNotEmpty) {
  print(snapshot.data);
  // 取列表第一个用户的username传入HomePage
  return HomePage(username: snapshot.data!.first.username);
} else {
  return Login();
}

额外优化(可选)

为了避免后续再出现类似问题,可以把HomePage的username改成必填参数:

class HomePage extends StatefulWidget {
  // 改成required且非空
  final String username;
  HomePage({required this.username});

  @override
  State<HomePage> createState() => _HomePageState();
}

这样编译器会在你忘记传参时直接报错,提前避免运行时错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 07:25:20