首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android SQLite 數據插入崩潰排查:空指針異常定位與數據庫操作最佳實踐

     編輯:程式設計綜合問答

常見崩潰原因分析

異常類型典型日誌根本原因解決方案
NullPointerExceptiondb.insert() / db.query() 崩潰SQLiteDatabase 實例為 null檢查 getWritableDatabase() 調用時機
SQLiteExceptionno such table / syntax error建表 SQL 錯誤 / 版本號未升級onCreate 執行建表 / onUpgrade 遷移
IllegalStateExceptiondatabase not open數據庫已關閉 / 多線程並發單例模式管理 / 同步鎖
SQLiteConstraintExceptionUNIQUE constraint failed主鍵/唯一鍵衝突insertOrReplace / 捕獲異常處理

標準數據庫助手類模板


public class DatabaseHelper extends SQLiteOpenHelper {
    private static final String DB_NAME = "myapp.db";
    private static final int DB_VERSION = 1;
    private static DatabaseHelper instance;
    private static final Object lock = new Object();
    
    // 單例模式
    public static DatabaseHelper getInstance(Context context) {
        synchronized (lock) {
            if (instance == null) {
                instance = new DatabaseHelper(context.getApplicationContext());
            }
            return instance;
        }
    }
    
    private DatabaseHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }
    
    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "CREATE TABLE user_data (" +
            "id INTEGER PRIMARY KEY AUTOINCREMENT, " +
            "name TEXT NOT NULL, " +
            "value TEXT, " +
            "create_time INTEGER DEFAULT (strftime('%s','now'))" +
            ")";
        db.execSQL(sql);
    }
    
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldV, int newV) {
        // 版本遷移邏輯
        db.execSQL("DROP TABLE IF EXISTS user_data");
        onCreate(db);
    }
    
    // 安全插入
    public long safeInsert(String table, ContentValues values) {
        SQLiteDatabase db = null;
        try {
            db = getWritableDatabase();
            return db.insert(table, null, values);
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        } finally {
            // 不要手動 close(),由 SQLiteOpenHelper 管理
        }
    }
}

Activity 中正確調用姿勢


public class MainActivity extends AppCompatActivity {
    private DatabaseHelper dbHelper;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        dbHelper = DatabaseHelper.getInstance(this);
        
        findViewById(R.id.btn_save).setOnClickListener(v -> {
            String name = ((EditText)findViewById(R.id.et_name)).getText().toString();
            String value = ((EditText)findViewById(R.id.et_value)).getText().toString();
            
            ContentValues cv = new ContentValues();
            cv.put("name", name);
            cv.put("value", value);
            
            long rowId = dbHelper.safeInsert("user_data", cv);
            if (rowId > 0) {
                Toast.makeText(this, "保存成功 ID:" + rowId, Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "保存失敗", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

調試技巧

  1. Logcat 過濾:`tag:SQLiteDatabase` 或 `tag:DatabaseHelper`
  2. 數據庫文件導出:`adb shell run-as com.yourpackage cp databases/myapp.db /sdcard/` → `adb pull /sdcard/myapp.db`
  3. SQLite 查看工具:DB Browser for SQLite / SQLiteStudio
  4. Stetho 調試:Chrome DevTools 直接查看 App 數據庫

新手避坑清單

  • ✅ 使用 `getApplicationContext()` 避免內存洩漏
  • ✅ 單例模式管理 SQLiteOpenHelper
  • ✅ 不要在 finally 中 close() 數據庫
  • ✅ 版本升級必須實現 onUpgrade 遷移邏輯
  • ✅ 所有數據庫操作捕獲異常防止崩潰
  • ✅ 使用 ContentValues 防止 SQL 注入
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved