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

Android中调用Database构造器的getWritableDatabase()致App崩溃

问题描述

我的Android应用在Database类中调用getWritableDatabase()方法时持续崩溃。移除getWritableDatabase()和getReadableDatabase()后应用可正常运行,但用户表因onCreate方法未执行而无法创建,该如何解决?

相关代码

MainActivity.java

package com.google.assignment_lab;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import com.google.assignment_lab.database.UserTable;


public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    Button mainRegisterButton, mainLoginButton;
    UserTable userTable = new UserTable(this);
    @Override

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mainRegisterButton = findViewById(R.id.mainRegisterButton);
        mainLoginButton = findViewById(R.id.mainLoginButton);
        mainRegisterButton.setOnClickListener(this);
        mainLoginButton.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
        Intent intent;

        if(view == mainRegisterButton){
            intent = new Intent(this, RegisterActivity.class);
            startActivity(intent);
        }

        if(view == mainLoginButton){
            intent = new Intent(this, LoginActivity.class);
            startActivity(intent);
        }
    }
}

UserTable.java

package com.google.assignment_lab.database;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import androidx.annotation.Nullable;

public class UserTable  extends SQLiteOpenHelper {

    public static String DATABASE_NAME = "MyData";
    public static int DATABASE_VERSION = 1;
    public static String TABLE_NAME = "Users";
    Context context;
    SQLiteDatabase database;

    public UserTable(@Nullable Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.context = context;
        database = getWritableDatabase();
        database = getReadableDatabase();
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        String query = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (username TEXT, password TEXT, email TEXT, phone TEXT)";
        sqLiteDatabase.execSQL(query);
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}

错误日志

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.google.assignment_lab, PID: 8732
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.google.assignment_lab/com.google.assignment_lab.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.File android.content.Context.getDatabasePath(java.lang.String)' on a null object reference
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3551)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3782)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2307)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:201)
    at android.os.Looper.loop(Looper.java:288)
    at android.app.ActivityThread.main(ActivityThread.java:7872)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.File android.content.Context.getDatabasePath(java.lang.String)' on a null object reference
    at android.content.ContextWrapper.getDatabasePath(ContextWrapper.java:380)
    at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:370)
    at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:316)
    at com.google.assignment_lab.database.UserTable.<init>(UserTable.java:20)
    at com.google.assignment_lab.MainActivity.<init>(MainActivity.java:16)
    at java.lang.Class.newInstance(Native Method)
    at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95)
    at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:45)
    at android.app.Instrumentation.newActivity(Instrumentation.java:1339)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3538)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3782) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2307) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loopOnce(Looper.java:201) 
    at android.os.Looper.loop(Looper.java:288) 
    at android.app.ActivityThread.main(ActivityThread.java:7872) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936) 
解决方案

问题根源

  1. Context为空导致崩溃:在MainActivity中,直接在成员变量位置初始化UserTable userTable = new UserTable(this);时,Activity还未完成初始化,this引用的Context无效(为空),调用getWritableDatabase()触发空指针异常。
  2. 初始化时机错误:SQLiteOpenHelper的getWritableDatabase()/getReadableDatabase()不需要在构造方法中调用,首次访问数据库时系统会自动调用这些方法,同时触发onCreate()创建表。

修改步骤

1. 调整MainActivity中UserTable的初始化时机

将UserTable的初始化移到onCreate()方法内部,此时Activity的Context已就绪:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    Button mainRegisterButton, mainLoginButton;
    UserTable userTable; // 先声明,不初始化

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        userTable = new UserTable(this); // 在这里初始化,Context已有效
        mainRegisterButton = findViewById(R.id.mainRegisterButton);
        mainLoginButton = findViewById(R.id.mainLoginButton);
        mainRegisterButton.setOnClickListener(this);
        mainLoginButton.setOnClickListener(this);
    }

    // ... 其他代码不变
}

2. 修正UserTable的构造方法

移除构造方法中对getWritableDatabase()和getReadableDatabase()的调用,改为在需要操作数据库时获取实例:

public class UserTable extends SQLiteOpenHelper {

    public static String DATABASE_NAME = "MyData";
    public static int DATABASE_VERSION = 1;
    public static String TABLE_NAME = "Users";
    Context context;
    SQLiteDatabase database;

    public UserTable(@Nullable Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.context = context;
        // 移除这里的getWritableDatabase()和getReadableDatabase()调用
    }

    // 添加获取数据库实例的方法,在需要时调用
    public SQLiteDatabase getDatabase() {
        if (database == null || !database.isOpen()) {
            database = getWritableDatabase();
        }
        return database;
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        String query = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (username TEXT, password TEXT, email TEXT, phone TEXT)";
        sqLiteDatabase.execSQL(query);
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        // 数据库升级时的处理逻辑,比如删除旧表重建
        sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
        onCreate(sqLiteDatabase);
    }
}

3. 触发表创建

当需要操作数据库(比如注册用户)时,调用getDatabase()方法,系统会自动检查数据库是否存在,不存在则创建并执行onCreate():

// 示例:在RegisterActivity中插入数据
UserTable userTable = new UserTable(this);
SQLiteDatabase db = userTable.getDatabase();
ContentValues values = new ContentValues();
values.put("username", "test");
values.put("password", "123456");
db.insert(UserTable.TABLE_NAME, null, values);

额外建议

  • 添加主键:给Users表增加主键字段(如id INTEGER PRIMARY KEY AUTOINCREMENT),避免数据重复,提升查询效率。
  • 使用ContentValues:插入/更新数据时用ContentValues替代直接拼接SQL,避免SQL注入风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 00:15:07