SQLiteOpenHelper的onCreate方法什么时候被调用?

32

我试图创建一个SQLite数据库并对其进行一些操作。但我发现我的onCreate方法甚至没有被调用!

我在onCreate方法的开头发送了一条消息到LogCat。

我的假设是,(super)构造函数将调用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;
    }

}
4个回答

36

6
让我来澄清一下逻辑流程。这里是“惰性初始化”概念。
在DatabaseHandler的(超级)构造函数中,不会调用onCreate方法。调用DatabaseHandler构造函数将初始化:上下文、数据库名称、创建数据库的工厂、数据库版本和数据库错误处理程序。
getWritableDatabase() > getDatabaseLocked() > - SQLiteDatabase.create()

getReadableDatabase() > getDatabaseLocked() > - SQLiteDatabase.create()
答案:当您的数据库成功创建后,配置更改,下一次再次调用getReadableDatabase()或getWritableDatabase()时,getDatabaseLocked()被调用,并且其中的onCreate(db)方法在getDatabaseLocked()中执行。

enter image description here

解释:

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 条件语句。这些条件语句确定您当前的环境(配置),并根据您当前的环境调用适当的方法来初始化/配置所需的内容。
此外,请注意:在您实现了 SQLiteOpenHelperDatabaseHandler 类中,所有回调方法都在 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,请按照此格式进行操作。


4
你是对的,(超级)构造函数会调用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)方法,这个类会负责打开数据库(如果存在),创建数据库(如果不存在)以及根据需要升级它。


1
根据官方文档,"getWritableDatabase()创建并/或打开用于读写的数据库。第一次调用此方法时,将打开数据库并调用onCreate(SQLiteDatabase)、onUpgrade(SQLiteDatabase, int, int)和/或onOpen(SQLiteDatabase)。"。
成功打开后,数据库会被缓存,因此每次需要写入数据库时都可以调用此方法。(确保在不再需要数据库时调用close()。)权限不足或磁盘已满等错误可能导致此方法失败,但如果问题得到解决,则未来的尝试可能会成功。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接