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()データベースが存在しない場合にのみ自動的に呼び出されます。これは1回だけ発生します。その後、データベースファイルはデバイスの内部ストレージに存在するため、所有しているバージョンをロードするだけです。

外部ファイルが変更されたときに新しいデータベースを作成する場合は、現在のデータベースファイルを削除するか(手動プロセス)、ヘルパーが作成された現在のデータベースバージョンも変更する必要があります。Androidは、バージョンSQLiteOpenHelperが内部ストレージ内の現在のファイルとは異なるもので作成されていることを確認するとonUpgrade()、既存のデータベースを新しい「バージョン」に一致するように変更できるようにするために呼び出します。

編集:

明確にするために、データベースを作成すると、アプリケーションのアセットとは別に、デバイスの内部ストレージにdbファイルが作成(および永続化)されます。アプリケーションを再実行すると、永続化されたデータストレージがクリアされないため(または、「永続化」されなくなります)、アプリケーションの最後の実行からのデータベースファイルが引き続き存在します...作成されました。

このクラスの変数に変更を加えても、デバイスにすでに存在するデータベースファイルが魔法のように変更されることはないため、存在しないテーブルとデータベース(おそらくクラッシュの発生元)を探しています。 )。

開発中に行った変更を反映するためにデータベースをクリアする必要がある場合は、[設定]->[アプリケーションの管理]->[{アプリケーション名}]->[データのクリア]に移動して、デバイスでデータベースを手動でクリアします。これにより、永続化されたファイルが削除されるため、次にアプリケーションを起動したときにアプリケーションで再作成できます。

ただし、これが何らかの形でアプリケーションが/assets内のファイルに加えた変更を自動的に認識し、その結果としてデータベースを変更または再作成する機能である必要がある場合は、アップグレードの使用に関する以前の提案を参照してください。に組み込まれたメカニズムSQLiteOpenHelper

HTH

于 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を呼び出します。データベース。だからあなたはチェックしてもっと次のようなことをする必要が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カードに書き込む必要があります。

于 2012-06-04T19:35:30.413 に答える