0

我遇到了一个非常令人沮丧的错误。

我有一个 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 文件中进行更改时,我在运行时看不到任何反映这些更改的内容。为什么会这样?

4

2 回答 2

3

SQLiteOpenHelper.onCreate()只有在数据库不存在时才会自动调用,这只会发生一次。之后,数据库文件存在于设备的内部存储中,因此它只会加载它拥有的版本。

如果要在更改外部文件时创建新数据库,则需要删除当前数据库文件(手动过程)或更改创建助手的当前数据库版本。当 Android 发现SQLiteOpenHelper创建的版本与内部存储中的当前文件不同时,它会调用onUpgrade()以允许修改现有数据库以匹配新的“版本”。

编辑:

澄清一下,当您创建数据库时,会在设备的内部存储上创建(并持久化)一个 db 文件,与应用程序的资产分开。当你重新运行你的应用程序时,持久化的数据存储不会被清除(否则它不会被“持久化”),所以你的应用程序最后一次运行的数据库文件仍然存在……所有的设置都是从​​什么时候开始的它被创造了。

当您更改此类中的变量时,它不会以某种方式神奇地修改设备上已经存在的数据库文件,因此现在您正在寻找不存在的表和数据库(可能是您的崩溃来自何处) )。

如果您只需要清除数据库以反映您在开发过程中所做的更改,只需在设备上手动清除数据库,方法是进入设置 -> 管理应用程序 -> {应用程序名称} -> 清除数据。这会删除持久文件,以便您的应用程序在下次启动时重新创建它们。

但是,如果您需要此功能以某种方式成为您的应用程序自动识别您对 /assets 中的文件所做的更改并因此修改或重新创建数据库的功能,那么请查看我之前关于使用升级的建议内置机制SQLiteOpenHelper

高温高压

于 2012-06-04T19:35:07.753 回答
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数据库。所以你需要检查oldVeresionnewVersion做更多类似的事情

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 卡。

于 2012-06-04T19:35:30.413 回答