SQLiteOpenHelper:未在物理设备上调用onCreate()方法

时间:2014-01-05 16:49:56

标签: android android-sqlite sqliteopenhelper android-sdk-2.3

我在4.4版中运行的android模拟器上做了很多测试。 在我的应用程序中,我使用SQLiteOpenHelper创建一个带有一个表的sqlite数据库:

package com.findwords.modeles;

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

import com.findwords.MainActivity;
import com.findwords.controleurs.MenuController;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * Created by louk on 02/01/14.
 */
public class DictionaryDbHelper extends SQLiteOpenHelper{

    // declare constants fields
    private static final String DB_PATH = "/data/data/com.findwords/databases/";
    private static final String DB_NAME = "dictionary_db";
    private static final int DB_VERSION = 1;

    // declared constant SQL Expression
    private static final String DB_CREATE =
            "CREATE TABLE dictionary ( " +
                    "_id integer PRIMARY KEY AUTOINCREMENT, " +
                    "word text NOT NULL, " +
                    "definition text NOT NULL, " +
                    "length integer NOT NULL " +
                    ");";

    private static final String DB_DESTROY =
            "DROP TABLE IF EXISTS dictionnary";

    /*
     * constructor
     */
    public DictionaryDbHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    /**
     * Creates a empty database on the system and rewrites it with your own database.
     * */
    public void createDataBase() throws IOException {

        boolean dbExist = checkDataBase();

        if(dbExist){
            //do nothing - database already exist
        }else{

            //By calling this method and empty database will be created into the default system path
            //of your application so we are gonna be able to overwrite that database with our database.
            this.getReadableDatabase();

            try {

                copyDataBase();

            } catch (IOException e) {

                throw new Error("Error copying database");

            }
        }

    }
    /**
     * Check if the database already exist to avoid re-copying the file each time you open the application.
     * @return true if it exists, false if it doesn't
     */
    private boolean checkDataBase(){

        SQLiteDatabase checkDB = null;

        try{
            String myPath = DB_PATH + DB_NAME;
            checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

        }catch(SQLiteException e){

            //database does't exist yet.

        }

        if(checkDB != null){

            checkDB.close();

        }

        return checkDB != null ? true : false;
    }

    /**
     * Copies your database from your local assets-folder to the just created empty database in the
     * system folder, from where it can be accessed and handled.
     * This is done by transfering bytestream.
     * */
    private void copyDataBase() throws IOException{

        //Open your local db as the input stream
        InputStream myInput = MenuController.getInstance().getMainActivity().getAssets().open(DB_NAME);

        // Path to the just created empty db
        String outFileName = DB_PATH + DB_NAME;

        //Open the empty db as the output stream
        OutputStream myOutput = new FileOutputStream(outFileName);

        //transfer bytes from the inputfile to the outputfile
        byte[] buffer = new byte[1024];
        int length;
        while ((length = myInput.read(buffer))>0){
            myOutput.write(buffer, 0, length);
        }

        //Close the streams
        myOutput.flush();
        myOutput.close();
        myInput.close();

    }

    /*
     * (non-Javadoc)
     * @see android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite.SQLiteDatabase)
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(DB_CREATE);

        try {
            createDataBase();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /*
     * (non-Javadoc)
     * @see android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite.SQLiteDatabase, int, int)
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL(DB_DESTROY);
        onCreate(db);
    }
}

此外,我已经编写了一个打开方法的适配器:

/*
 * open database connection
 */
public DictionaryDbAdapter open() throws SQLException {
    mDbHelper = new DictionaryDbHelper(mContext);
    mDb = mDbHelper.getWritableDatabase();
    return this;
}

它在模拟器上运行良好,因此SQLiteOpenHelper类的onCreate()方法被调用并创建数据库,但未在我的手机上调用(Google Nexus 5)。

我的手机没有root权限,因此我无法访问文件夹/data/data/com.myapp/databases。

但是我希望这个应用程序可以在任何手机上运行,​​所以我不想根我的手机。

提前感谢任何可以帮助我的人。

3 个答案:

答案 0 :(得分:5)

仅在第一次调用onCreate方法时 - 实际创建数据库时。因此,如果您卸载应用程序然后重新安装它 - 它将被调用,但如果您安装在现有副本之上onCreate将不会被调用(因为数据库已经存在)

答案 1 :(得分:5)

让我试着向你解释一些事情。

在连接数据库的应用程序中,我们指定数据库的名称和版本。在这种情况下,可能会发生以下情况:

1)没有数据库。这可以是例如初始设定程序的情况。在这种情况下,应用程序本身必须创建数据库及其中的所有表。此外,它已经在使用新创建的数据库。

2)数据库存在,但其版本已过时。可能是案例更新。例如,程序的新版本需要旧表或新表中的附加字段。在这种情况下,应用程序必须更新现有表并在必要时创建新表。

3)有一个数据库及其实际版本。在这种情况下,应用程序成功连接到数据库并运行。

如您所知,短语“应用程序必须”等同于“开发人员必须”这一短语,即这是我们的任务。要处理上述情况,我们需要创建一个继承SQLiteOpenHelper的类。称之为DBHelper。该类将为我们提供在数据库不存在或过时的情况下创建或更新数据库的方法。

onCreate - 如果我们要连接的数据库不存在将被调用的方法(这是你的情况)

答案 2 :(得分:1)

正如@Asahi所说,只有在重新安装应用程序时才会创建数据库。但是,既然你说我的手机没有根,所以我无法访问文件夹/data/data/com.myapp/databases ,我想指出你可以将手机连接到电脑,安装正确的 USB驱动程序并使用 DDMS 查看手机的文件结构。在那里,您可以看到应用程序的数据库以及共享首选项和其他文件。

PS: - 要查看ddms上所有真实设备的文件夹,您需要 root access 。如果您的设备没有root,并且您不想根设置,那么您可以在模拟器上安装该设备,该模拟器显示DDMS中的所有文件夹。