【问题标题】:SQLiteOpenHelper: onCreate() method not called on physical deviceSQLiteOpenHelper:物理设备上未调用 onCreate() 方法
【发布时间】:2014-01-06 02:02:18
【问题描述】:

我在 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 方法的适配器:

/*
 * 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 。

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

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

【问题讨论】:

  • 卸载应用重新安装,会被调用

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


【解决方案1】:

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

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

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

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

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

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

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

【讨论】:

  • 感谢您的解释。我以为在 android-studio 上运行该应用程序之前已卸载该应用程序,但事实并非如此。我刚刚在手机上卸载了该应用程序,它在下次运行时正确创建了数据库。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 感谢您的回答,但我仍然无法从 ddms 访问数据文件夹。当我单击“数据”时,它在 ddms 中什么也不做。使用 adb 访问此文件夹时出现错误:opendir failed, Permission denied
    • @Chewbye 我忘了说这需要 root 访问权限
    • 我在adb中使用这个命令找到了解决方案:run-as com.yourapp
    • @Chewbye 查看我的更新答案和仅供参考,如果您看到任何有用的答案,请点赞。
    猜你喜欢
    • 2013-03-13
    • 1970-01-01
    • 1970-01-01
    • 2011-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多