我遇到了一个非常令人沮丧的错误。
我有一个java类,它从文件中读取数据,然后将其输入数据库。
package edu.uci.ics.android;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DbAdapter extends SQLiteOpenHelper{
private static final String DATABASE_NAME = "mydb";
private static final int DATABASE_VERSION = 1;
private static final String TABLE_NAME = "fruits";
private static final String FRUIT_ID = "_id";
private static final String FRUIT_NAME = "name";
private static final String FILE_NAME = "fruits.txt";
private static final String CREATE_TABLE = "CREATE TABLE "+ TABLE_NAME + "("+FRUIT_ID+" integer primary key autoincrement, "+FRUIT_NAME+" text not null);";
private SQLiteDatabase mDb;
private Context mContext;
public DbAdapter(Context ctx){
super(ctx, DATABASE_NAME, null, DATABASE_VERSION);
mContext = ctx;
this.mDb = getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
// populate database
try {
BufferedReader in = new BufferedReader(new InputStreamReader(mContext.getAssets().open(FILE_NAME)));
String line;
while((line=in.readLine())!=null) {
ContentValues values = new ContentValues();
values.put(FRUIT_NAME, line);
db.insert(TABLE_NAME, null, values);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS "+TABLE_NAME);
onCreate(db);
}
public Cursor fetchAll() {
return mDb.query(TABLE_NAME, new String[] {FRUIT_NAME}, null, null, null, null, null);
}
}
编辑:
更清楚的是,这是失败的:
当我更改数据库名称变量,表名变量时,程序强制关闭,表明出现了问题。为什么我不能更改我创建的表的名称?
当我在fruits.txt文件中进行更改时,我在运行时看不到任何反映这些更改的内容。为什么会这样?
答案 0 :(得分:3)
SQLiteOpenHelper.onCreate()
,这只会发生一次。之后,数据库文件存在于设备的内部存储器中,因此它只是加载它拥有的版本。
如果要在更改外部文件时创建新数据库,则需要删除当前数据库文件(手动过程)或更改创建帮助程序的当前数据库版本。当Android看到创建的版本SQLiteOpenHelper
与内部存储中的当前文件不同时,它将调用onUpgrade()
以允许修改现有数据库以匹配新的“版本”。
编辑:
为了澄清,在创建数据库时,会在设备的内部存储上创建(并保留)db文件,与应用程序的资产分开。当您重新运行应用程序时,持久性数据存储不会清除(或者它不再“持久化”),以便上次运行应用程序时的数据库文件仍然存在...具有从何时开始的所有设置它被创造了。
当您对此类中的变量进行更改时,它不会以某种方式神奇地修改设备上已存在的数据库文件,因此现在您正在查找不存在的表和数据库(可能是您崩溃的地方)来自)。
如果您只是需要清除数据库以便它反映您在开发过程中所做的更改,只需在设备上手动清除数据库,然后进入设置 - >管理应用程序 - > {Application Name} - >清除数据。这会删除持久文件,以便下次启动时可以由应用程序重新创建它们。
但是,如果您需要以某种方式将应用程序自动识别您对/ assets中的文件所做的更改并修改或重新创建数据库,那么请查看我以前的建议使用SQLiteOpenHelper
HTH
答案 1 :(得分:0)
当您在代码中更改数据库名称或表名称时,它们不再反映设备上数据库中的名称,因此您可以关闭力。在开发过程中,最简单的方法是卸载您的应用程序,然后在您进行类似的不兼容更改时重新安装。将数据库架构从一个已发布的版本更改为另一个版本时,需要增加数据库版本号并在onUpgrade()
中执行正确的操作。
例如,现在,你有
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS "+TABLE_NAME);
onCreate(db);
}
因此,当您更改代码中的表名称,将“fruits”更改为“veggies”时,onUpgrade()
会运行,但表veggies
不存在,因此不会删除,然后你在现有数据库之上调用onCreate(db)
一个冲突的shchema。因此,您需要检查oldVeresion
和newVersion
并执行更多类似
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion == 2 && oldVersion == 1) {
db.execSQL("DROP TABLE IF EXISTS" + TABLE_NAME_V1);
db.execSQL("CREATE TABLE "+ TABLE_NAME ...);
}
}
如果您尝试更改设备上的fruits.txt
,则无法使用。这就是Android的设计方式:您的资产永远不会改变,它们是您APK的只读部分。如果您希望能够更改它,则需要将fruit.txt
文件写入SD卡。