第一次打开数据库触发 OnCreate 时,无法从 SQLIte Helper Oncreate 打开 SQLite 数据库
Cannot open SQLite database from SQLIte Helper Oncreate, when OnCreate is triggered by opening database for the first time
当 mainactivity 在应用程序安装后第一次尝试打开数据库时,将触发 SQLiteHelper Oncreate 方法(正如人们所预料的那样)。我想在 OnCreate 中创建数据表后填充数据库,但这样做需要我在内容创建器 class(从 OnCreate 调用)中再次打开数据库。应用程序在内容创建器中尝试打开数据库时崩溃 class
基本上,我试图在创建数据库后填充它,但显然没有以正确的方式进行。
来自 SQLiteHelper Class:
...
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_TABLE); //sql string to create the table
dbContents.baseContents(sqcontext);
}
来自内容创作者class:
public class dbContents {
public static void baseContents(Context context) {
dbDataSource ds = new dbDataSource(context);
ds.open();
...
来自 dbDataSource Class:
public dbDataSource(Context context) {
dbHelper = new MySQLiteHelper(context);
DatabaseVersion = dbHelper.DatabaseVersion; //used when MainActivity onResume to know if it needs to repopulate reminders
}
public void open() throws SQLException {
database = dbHelper.getWritableDatabase(); //crashes here
}
...
它似乎在 database = dbHelper.getWritableDatabase() 行崩溃了;在 open() 方法中。重申一下,在主 activity 中打开数据库时调用 SQLiteHelper OnCreate。当数据库在 mainactivity 中打开时,它调用上面发布的相同的 open() 方法,当从 dbcontents class 调用时它崩溃了。这是线程问题吗?
您不应尝试从 SQLiteOpenHelper
生命周期方法(例如 onCreate()
或从那里调用的方法)调用 getWritableDatabase()
或 getReadableDatabase()
。这将失败并出现 "called recursively" 异常。
而是使用作为参数提供给 onCreate()
或其他生命周期方法的 SQLiteDatabase
。
我已经编写了一些代码片段来帮助您填充 SQLite Database
,代码在 Github 上可用,您可以查看工作示例。
创建一个 class 名称 CreateDatabase.java
,它的全部目的是创建数据库并向其中添加一个 table。
public class CreateDatabase extends SQLiteOpenHelper implements BaseColumns {
private static final String DATABASE_NAME = "database_name.sqlite";
private static final int DATABASE_VERSION = 1;
public static final String TEXT_TYPE = " TEXT";
public static final String COMMA_SEP = ",";
public CreateDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.d("CreateDatabase: ","onCreate: called for the first time");
db.execSQL(SQL_CREATE_TEST_ONE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public static final String SQL_CREATE_TEST_ONE_TABLE = "CREATE TABLE IF NOT EXISTS " + "TestOne_Table" +
" (" + BaseColumns._ID + " INTEGER PRIMARY KEY," +
"first_column_name" + TEXT_TYPE + COMMA_SEP +
"second_column_name" + TEXT_TYPE + ")";
}
现在你有了这个 class 你需要找到一种方法来使用它在应用程序启动后立即创建你的数据库,因为你知道 onCreate()
只会被调用一次,所以下面的代码只对第一次创建数据库很重要,把它放在应用程序打开时可以调用的地方。
CreateDatabase createAllTables = new CreateDatabase(getApplicationContext());
SQLiteDatabase database = createAllTables.getWritableDatabase();
这些行将帮助您创建数据库。
这些行已经运行之后,你可以在DDMS
中看到database
这样的,你可以在SQLite Browser
或Mozilla Sqlit Manager
成功创建数据库后,您可以使用以下代码向其中填充一些数据,我已将一些值作为示例进行展示。
public class SqliteTestOneActivity extends AppCompatActivity {
private Button save_Button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sqlite_test_one);
initializeUI();
}
private void initializeUI() {
save_Button = (Button) findViewById(R.id.SqliteTestOneActivity_button);
save_Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyReader myReader = new MyReader(getApplicationContext());
myReader.open();
myReader.insert("Jack", "Sam");
myReader.close();
}
});
}
private static class MyReader {
private static final String Table_Name = "TestOne_Table";
private final Context mCtx;
private SQLiteDatabase mDb;
private InternalHelper mDbHelper;
public MyReader(Context mCtx) {
this.mCtx = mCtx;
}
public MyReader open() {
this.mDbHelper = new InternalHelper(this.mCtx);
this.mDb = mDbHelper.getWritableDatabase();
return this;
}
public void insert(String first, String second) {
ContentValues values = new ContentValues();
values.put("first_column_name", first);
values.put("second_column_name", second);
mDb.insert(Table_Name, null, values);
}
public void close() {
if (mDbHelper != null) {
mDbHelper.close();
}
}
private static class InternalHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "database_name.sqlite";
private static final int DATABASE_VERSION = 1;
public InternalHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase paramSQLiteDatabase) {
}
public void onUpgrade(SQLiteDatabase paramSQLiteDatabase, int paramInt1, int paramInt2) {
}
}
}
}
一旦你运行这个activity点击保存按钮,你的数据就会保存在数据库中,你可以从DDMS中拉取数据库并检查记录
Output
当 mainactivity 在应用程序安装后第一次尝试打开数据库时,将触发 SQLiteHelper Oncreate 方法(正如人们所预料的那样)。我想在 OnCreate 中创建数据表后填充数据库,但这样做需要我在内容创建器 class(从 OnCreate 调用)中再次打开数据库。应用程序在内容创建器中尝试打开数据库时崩溃 class
基本上,我试图在创建数据库后填充它,但显然没有以正确的方式进行。
来自 SQLiteHelper Class:
...
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_TABLE); //sql string to create the table
dbContents.baseContents(sqcontext);
}
来自内容创作者class:
public class dbContents {
public static void baseContents(Context context) {
dbDataSource ds = new dbDataSource(context);
ds.open();
...
来自 dbDataSource Class:
public dbDataSource(Context context) {
dbHelper = new MySQLiteHelper(context);
DatabaseVersion = dbHelper.DatabaseVersion; //used when MainActivity onResume to know if it needs to repopulate reminders
}
public void open() throws SQLException {
database = dbHelper.getWritableDatabase(); //crashes here
}
...
它似乎在 database = dbHelper.getWritableDatabase() 行崩溃了;在 open() 方法中。重申一下,在主 activity 中打开数据库时调用 SQLiteHelper OnCreate。当数据库在 mainactivity 中打开时,它调用上面发布的相同的 open() 方法,当从 dbcontents class 调用时它崩溃了。这是线程问题吗?
您不应尝试从 SQLiteOpenHelper
生命周期方法(例如 onCreate()
或从那里调用的方法)调用 getWritableDatabase()
或 getReadableDatabase()
。这将失败并出现 "called recursively" 异常。
而是使用作为参数提供给 onCreate()
或其他生命周期方法的 SQLiteDatabase
。
我已经编写了一些代码片段来帮助您填充 SQLite Database
,代码在 Github 上可用,您可以查看工作示例。
创建一个 class 名称 CreateDatabase.java
,它的全部目的是创建数据库并向其中添加一个 table。
public class CreateDatabase extends SQLiteOpenHelper implements BaseColumns {
private static final String DATABASE_NAME = "database_name.sqlite";
private static final int DATABASE_VERSION = 1;
public static final String TEXT_TYPE = " TEXT";
public static final String COMMA_SEP = ",";
public CreateDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.d("CreateDatabase: ","onCreate: called for the first time");
db.execSQL(SQL_CREATE_TEST_ONE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public static final String SQL_CREATE_TEST_ONE_TABLE = "CREATE TABLE IF NOT EXISTS " + "TestOne_Table" +
" (" + BaseColumns._ID + " INTEGER PRIMARY KEY," +
"first_column_name" + TEXT_TYPE + COMMA_SEP +
"second_column_name" + TEXT_TYPE + ")";
}
现在你有了这个 class 你需要找到一种方法来使用它在应用程序启动后立即创建你的数据库,因为你知道 onCreate()
只会被调用一次,所以下面的代码只对第一次创建数据库很重要,把它放在应用程序打开时可以调用的地方。
CreateDatabase createAllTables = new CreateDatabase(getApplicationContext());
SQLiteDatabase database = createAllTables.getWritableDatabase();
这些行将帮助您创建数据库。
这些行已经运行之后,你可以在DDMS
中看到database
这样的,你可以在SQLite Browser
或Mozilla Sqlit Manager
成功创建数据库后,您可以使用以下代码向其中填充一些数据,我已将一些值作为示例进行展示。
public class SqliteTestOneActivity extends AppCompatActivity {
private Button save_Button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sqlite_test_one);
initializeUI();
}
private void initializeUI() {
save_Button = (Button) findViewById(R.id.SqliteTestOneActivity_button);
save_Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyReader myReader = new MyReader(getApplicationContext());
myReader.open();
myReader.insert("Jack", "Sam");
myReader.close();
}
});
}
private static class MyReader {
private static final String Table_Name = "TestOne_Table";
private final Context mCtx;
private SQLiteDatabase mDb;
private InternalHelper mDbHelper;
public MyReader(Context mCtx) {
this.mCtx = mCtx;
}
public MyReader open() {
this.mDbHelper = new InternalHelper(this.mCtx);
this.mDb = mDbHelper.getWritableDatabase();
return this;
}
public void insert(String first, String second) {
ContentValues values = new ContentValues();
values.put("first_column_name", first);
values.put("second_column_name", second);
mDb.insert(Table_Name, null, values);
}
public void close() {
if (mDbHelper != null) {
mDbHelper.close();
}
}
private static class InternalHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "database_name.sqlite";
private static final int DATABASE_VERSION = 1;
public InternalHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase paramSQLiteDatabase) {
}
public void onUpgrade(SQLiteDatabase paramSQLiteDatabase, int paramInt1, int paramInt2) {
}
}
}
}
一旦你运行这个activity点击保存按钮,你的数据就会保存在数据库中,你可以从DDMS中拉取数据库并检查记录
Output