【问题标题】:When the SQLiteOpenHelper onCreate method is called?何时调用 SQLiteOpenHelper onCreate 方法?
【发布时间】:2013-03-13 22:22:36
【问题描述】:

我尝试创建一个 SQLite 数据库并用它做一些事情。但是我发现我的onCreate 方法甚至没有被调用!!

我在 onCreate 方法的开头向 LogCat 发送消息。

我的假设是,(超级)构造函数将调用onCreate 方法。对吗?

我的代码:

import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
import android.content.Context;
import android.database.Cursor;
import android.content.ContentValues;
import android.util.Log;

public class DatabaseHandler extends SQLiteOpenHelper {
    // Static Constants
    /*** Database details ***/
    // Database version
    private static final int DATABASE_VERSION           = 1;

    // Database name
    private static final String DATABASE_NAME           = "database_name";

    /*** Database Tables ***/
    /** Events **/
    // Event table
    private static final String TABLE_EVENT             = "event";

    // Event table columns
    private static final String COLUMN_EVENT_EID        = "_eid";

    private static final String COLUMN_EVENT_CREATION_DATE  = "creation_date";

    private static final String COLUMN_EVENT_TITLE      = "title";
    private static final String COLUMN_EVENT_ICON       = "icon";

    public DatabaseHandler(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.e("MyApp", "onCreate invoked");
        // Tables creation queries
        String CREATE_EVENT_TABLE = "create table " + TABLE_EVENT + "(" + COLUMN_EVENT_EID + " integer primary key, "
                + COLUMN_EVENT_CREATION_DATE + " text, "
                + COLUMN_EVENT_TITLE + " text, "
                + COLUMN_EVENT_ICON + " text)";

        // Creating tables
        db.execSQL(CREATE_EVENT_TABLE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.e("MyApp", "onUpgrade invoked");
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_EVENT);
    }
}

MainActivity 代码:

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DatabaseHandler db = new DatabaseHandler(this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

【问题讨论】:

    标签: sqlite android-sqlite


    【解决方案1】:

    让我清除一下逻辑流程。这是延迟初始化的概念。

    DatabaseHandler 上的(超级)构造函数不会调用 onCreate 方法。调用 DatabaseHandler 构造函数将初始化:上下文、数据库名称、创建数据库的工厂、数据库版本和数据库错误处理程序。

    getWritableDatabase() > getDatabaseLocked() > - SQLiteDatabase.create()

    getReadableDatabase() > getDatabaseLocked() > - SQLiteDatabase.create()

    答案: 成功创建数据库后,您的配置会更改,下一次getReadableDatabase()getWritableDatabase() 调用getDatabaseLocked() 并在getDatabaseLocked() 中执行onCreate(db) 方法。

    说明:

    上面的SQLiteDatabase.create()方法负责在磁盘中创建SQLiteDatabase。

    但是延迟初始化的过程(意思是,它不会让一切准备就绪。如果需要,它会在运行时创建这些对象。为此它使用了很多 if..else 语句)。

    如果您看到getDatabaseLocked() 的全文,则如下所示。 [你可以在getDatabaseLocked()的正文中搜索onCreate()方法]

    private SQLiteDatabase getDatabaseLocked(boolean writable) {
            if (mDatabase != null) {
                if (!mDatabase.isOpen()) {
                    // Darn!  The user closed the database by calling mDatabase.close().
                    mDatabase = null;
                } else if (!writable || !mDatabase.isReadOnly()) {
                    // The database is already open for business.
                    return mDatabase;
                }
            }
    
            if (mIsInitializing) {
                throw new IllegalStateException("getDatabase called recursively");
            }
    
            SQLiteDatabase db = mDatabase;
            try {
                mIsInitializing = true;
    
                if (db != null) {
                    if (writable && db.isReadOnly()) {
                        db.reopenReadWrite();
                    }
                } else if (mName == null) {
                    db = SQLiteDatabase.create(null);
                } else {
                    try {
                        if (DEBUG_STRICT_READONLY && !writable) {
                            final String path = mContext.getDatabasePath(mName).getPath();
                            db = SQLiteDatabase.openDatabase(path, mFactory,
                                    SQLiteDatabase.OPEN_READONLY, mErrorHandler);
                        } else {
                            db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
                                    Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
                                    mFactory, mErrorHandler);
                        }
                    } catch (SQLiteException ex) {
                        if (writable) {
                            throw ex;
                        }
                        Log.e(TAG, "Couldn't open " + mName
                                + " for writing (will try read-only):", ex);
                        final String path = mContext.getDatabasePath(mName).getPath();
                        db = SQLiteDatabase.openDatabase(path, mFactory,
                                SQLiteDatabase.OPEN_READONLY, mErrorHandler);
                    }
                }
    
                onConfigure(db);
    
                final int version = db.getVersion();
                if (version != mNewVersion) {
                    if (db.isReadOnly()) {
                        throw new SQLiteException("Can't upgrade read-only database from version " +
                                db.getVersion() + " to " + mNewVersion + ": " + mName);
                    }
    
                    db.beginTransaction();
                    try {
                        if (version == 0) {
                            onCreate(db);
                        } else {
                            if (version > mNewVersion) {
                                onDowngrade(db, version, mNewVersion);
                            } else {
                                onUpgrade(db, version, mNewVersion);
                            }
                        }
                        db.setVersion(mNewVersion);
                        db.setTransactionSuccessful();
                    } finally {
                        db.endTransaction();
                    }
                }
    
                onOpen(db);
    
                if (db.isReadOnly()) {
                    Log.w(TAG, "Opened " + mName + " in read-only mode");
                }
    
                mDatabase = db;
                return db;
            } finally {
                mIsInitializing = false;
                if (db != null && db != mDatabase) {
                    db.close();
                }
            }
        }
    

    请注意,在getDatabaseLocked() 方法的主体内部,有很多 if.. else 情况。这些 if.. else 案例决定了您当前的环境(配置),并根据您当前的环境调用适当的方法来初始化/配置所需的任何内容。

    另外,请注意:DatabaseHandler(实现SQLiteOpenHelper 的类)中的所有回调方法都在getDatabaseLocked() 主体内调用。

    源码SQLiteOpenHelper.javahttps://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/database/sqlite/SQLiteOpenHelper.java

    源码SQLiteDatabase.javahttps://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/database/sqlite/SQLiteDatabase.java

    要遵循的示例:https://github.com/uddhavgautam/SQLiteBasicSample

    【讨论】:

      【解决方案2】:

      正如官方文档所说,“getWritableDatabase() 创建和/或打开一个将用于读写的数据库。第一次调用这个时,将打开数据库并onCreate (SQLiteDatabase)、onUpgrade(SQLiteDatabase, int, int) 和/或 onOpen(SQLiteDatabase) 将被调用。”

      一旦打开成功,数据库就会被缓存,所以每次需要写入数据库时​​都可以调用该方法。 (确保在不再需要数据库时调用 close()。)权限错误或磁盘已满等错误可能会导致此方法失败,但如果问题得到解决,以后的尝试可能会成功。

      http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#getWritableDatabase()

      【讨论】:

        【解决方案3】:

        你是对的,(超级)构造函数将调用 onCreate 方法,但仅当实际数据库不退出时。 来自http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#onCreate%28android.database.sqlite.SQLiteDatabase%29

        管理数据库创建和版本管理的帮助类。

        您创建一个实现 onCreate(SQLiteDatabase) 的子类, onUpgrade(SQLiteDatabase, int, int) 和可选 onOpen(SQLiteDatabase),这个类负责打开 如果存在,则创建数据库,如果不存在,则创建它,并将其升级为 必要的。

        【讨论】:

          【解决方案4】:

          documentation 说:

          在调用getWritableDatabase()getReadableDatabase() 之一之前,不会实际创建或打开数据库。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-06-28
            • 1970-01-01
            • 1970-01-01
            • 2016-09-17
            相关资源
            最近更新 更多