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

解决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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 08:57:18