解决Null check operator空值错误及Sqlite跨页面传数据问题
解决 Null check operator 错误及 SQLite 数据处理方案
一、定位并修复空值检查错误
从你贴的代码截图看,问题核心是滥用非空断言!,但对应的变量实际为null——哪怕你加了空值检查,要么是检查逻辑没覆盖到,要么是操作时机不对(比如数据库还没初始化完成就调用了操作)。
具体修复动作:
- 删掉所有硬写的
!,替换为安全调用?.,或者提前做明确的空值拦截:// 错误写法 await database!.insert(...); // 正确写法 final db = await LocalDatabase.database; // 用单例确保数据库已初始化 await db.insert(...); - 检查
LocalDatabase的初始化逻辑:必须等openDatabase的Future完成后再调用数据库操作,绝对不能在初始化未完成时用!断言。
二、LocalDatabase 完整实现(插入+跨页数据传递)
1. 数据库核心代码
import 'package:sqflite/sqflite.dart'; import 'package:path/path.dart'; class LocalDatabase { static Database? _database; // 单例模式,确保数据库只初始化一次 static Future<Database> get database async { if (_database != null) return _database!; _database = await _initDB(); return _database!; } static Future<Database> _initDB() async { final dbPath = await getDatabasesPath(); final path = join(dbPath, 'local_database.db'); return await openDatabase( path, version: 1, onCreate: (db, version) async { // 创建用户表,按需调整字段 await db.execute(''' CREATE TABLE users( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password TEXT NOT NULL ) '''); }, ); } // 插入用户数据 static Future<int> insertUser(Map<String, dynamic> user) async { final db = await database; return await db.insert( 'users', user, conflictAlgorithm: ConflictAlgorithm.replace, // 重复用户名时覆盖 ); } // 查询用户(登录验证+跨页传递用) static Future<Map<String, dynamic>?> getUser(String username) async { final db = await database; final result = await db.query( 'users', where: 'username = ?', whereArgs: [username], ); return result.isNotEmpty ? result.first : null; } }
2. 登录按钮逻辑(插入+跳转)
// 假设你用了TextEditingController获取输入 final _usernameCtrl = TextEditingController(); final _passwordCtrl = TextEditingController(); // 登录按钮点击事件 onPressed: () async { final username = _usernameCtrl.text.trim(); final password = _passwordCtrl.text.trim(); // 先做前端空值校验 if (username.isEmpty || password.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('请输入完整的用户名和密码')), ); return; } try { // 插入数据到SQLite await LocalDatabase.insertUser({ 'username': username, 'password': password, }); // 查询用户数据,用于跨页传递 final user = await LocalDatabase.getUser(username); if (user != null) { // 跳转到目标页面并传递数据 Navigator.push( context, MaterialPageRoute( builder: (_) => HomePage(userInfo: user), ), ); } } catch (e) { print('数据库操作失败:$e'); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('登录失败:$e')), ); } },
3. 接收页面代码
class HomePage extends StatelessWidget { final Map<String, dynamic> userInfo; const HomePage({super.key, required this.userInfo}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('主页')), body: Center( child: Text('欢迎回来,${userInfo['username']}!'), ), ); } }
三、避坑要点
- 永远别在不确定变量是否为null时用
!,优先用单例模式确保数据库实例已初始化,或者用?.+空值判断。 - 所有数据库操作必须包裹在
async/await中,异步操作未完成前不要执行后续逻辑。 - 如果跨页传递的是复杂数据,建议用Provider、Riverpod等状态管理工具,避免直接传递大对象导致性能问题。
内容的提问来源于stack exchange,提问作者Satoru Gojo
相关产品推荐
相关产品推荐

