Sqlite 源码分析 -- SQLiteOpenHelper (API 14)

使用注意事项:

  1. getWritableDatabase() 不要放在 UI 线程,存在阻塞和操作耗时的情况;
  2. getReadableDatabase() 优先返回 getWritableDatabase(), 发生 SQLiteException 异常后,才尝试获取只读模式的数据库
  3. getReadableDatabase() 由于调用了 getWritableDatabase(), 同样不能放在 UI 线程

一、构造方法

/**
 * 该方法会快速返回,并不会创建或打开数据库
 * 
 * Create a helper object to create, open, and/or manage a database.
 * This method always returns very quickly.  The database is not actually
 * created or opened until one of {@link #getWritableDatabase} or
 * {@link #getReadableDatabase} is called.
 *
 * @param context to use to open or create the database
 * @param name of the database file, or null for an in-memory database
 * @param factory to use for creating cursor objects, or null for the default
 * @param version number of the database (starting at 1); if the database is older,
 *     {@link #onUpgrade} will be used to upgrade the database; if the database is
 *     newer, {@link #onDowngrade} will be used to downgrade the database
 */
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
    this(context, name, factory, version, new DefaultDatabaseErrorHandler());
}


public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
                        DatabaseErrorHandler errorHandler) {
    if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
    if (errorHandler == null) {
        throw new IllegalArgumentException("DatabaseErrorHandler param value can't be null.");
    }

    mContext = context;
    mName = name;
    mFactory = factory;
    mNewVersion = version;
    mErrorHandler = errorHandler;
}

二、getWritableDatabase()

/**
 * 第一次调用该方法时,将会打开数据库,并会视情况调用 onCreate(), onUpgrade(), onDowngrade(), onOpen()
 *
 * 该方法的调用不要放在 UI 线程,存在阻塞和操作耗时的情况
 *
 * Create and/or open a database that will be used for reading and writing.
 * The first time this is called, the database will be opened and
 * {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} will be
 * called.
 *
 * 

Once opened successfully, the database is cached, so you can * call this method every time you need to write to the database. * (Make sure to call {@link #close} when you no longer need the database.) * Errors such as bad permissions or a full disk may cause this method * to fail, but future attempts may succeed if the problem is fixed.

* *

Database upgrade may take a long time, you * should not call this method from the application main thread, including * from {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}. * * @throws SQLiteException if the database cannot be opened for writing * @return a read/write database object valid until {@link #close} is called */ public synchronized SQLiteDatabase getWritableDatabase() { if (mDatabase != null) { if (!mDatabase.isOpen()) { // 若是 mDatabase 已被关闭,则置空, 重新获取 // darn! the user closed the database by calling mDatabase.close() mDatabase = null; } else if (!mDatabase.isReadOnly()) { // mDatabase 已满足条件,直接返回 // The database is already open for business return mDatabase; } } if (mIsInitializing) { // 该方法不允许被递归调用 throw new IllegalStateException("getWritableDatabase called recursively"); } // If we have a read-only database open, someone could be using it // (though they shouldn't), which would cause a lock to be held on // the file, and our attempts to open the database read-write would // fail waiting for the file lock. To prevent that, we acquire the // lock on the read-only database, which shuts out other users. boolean success = false; SQLiteDatabase db = null; if (mDatabase != null){ /** * 应对之前获取的是只读数据库的情况 * 等待该线程获取到锁对象后返回,此处可能造成阻塞 */ mDatabase.lock(); } try { mIsInitializing = true; if (mName == null) { db = SQLiteDatabase.create(null); } else { /** * 层层跟进,最终: * db = new SQLiteDatabase(path, factory, flags, errorHandler, connectionNum) * 注意此处的 mode:0 == SQLiteDatabase.OPEN_READWRITE, 即可读写模式 */ db = mContext.openOrCreateDatabase(mName, 0, mFactory, mErrorHandler); } int version = db.getVersion(); if (version != mNewVersion) { db.beginTransaction(); try { if (version == 0) { /** * 数据库不存在时才会调用 onCreate() * 由子类实现数据库的创建 */ onCreate(db); } else { if (version > mNewVersion) { // 需要注意降版本的情况,该方法的默认实现是抛出异常 onDowngrade(db, version, mNewVersion); } else { // 由子类实现升级数据库版本 onUpgrade(db, version, mNewVersion); } } db.setVersion(mNewVersion); db.setTransactionSuccessful(); } finally { db.endTransaction(); } } // onOpen 为空实现 onOpen(db); success = true; return db; } finally { // 注意此处对 try 语句的用法,只有 finally 语句块,没有 catch 语句块 mIsInitializing = false; if (success) { /** * 成功获取到可读写的数据库 */ if (mDatabase != null) { try { mDatabase.close(); } catch (Exception e) { } mDatabase.unlock(); } // 注意此处,把获取到的可读写数据库赋值给 mDatabase mDatabase = db; } else { if (mDatabase != null){ mDatabase.unlock(); } if (db != null) db.close(); } } }

三、getReadableDatabase()

/**
 * 该方法的调用不要放在 UI 线程,存在阻塞和操作耗时的情况
 * 优先返回 getWritableDatabase()
 * getWritableDatabase() 发生 SQLiteException 异常后,才尝试获取只读模式的数据库
 *
 * Create and/or open a database.  This will be the same object returned by
 * {@link #getWritableDatabase} unless some problem, such as a full disk,
 * requires the database to be opened read-only.  In that case, a read-only
 * database object will be returned.  If the problem is fixed, a future call
 * to {@link #getWritableDatabase} may succeed, in which case the read-only
 * database object will be closed and the read/write object will be returned
 * in the future.
 *
 * 

Like {@link #getWritableDatabase}, this method may * take a long time to return, so you should not call it from the * application main thread, including from * {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}. * * @throws SQLiteException if the database cannot be opened * @return a database object valid until {@link #getWritableDatabase} * or {@link #close} is called. */ public synchronized SQLiteDatabase getReadableDatabase() { if (mDatabase != null) { if (!mDatabase.isOpen()) { // darn! the user closed the database by calling mDatabase.close() // 若是 mDatabase 已被关闭,则置空, 重新获取 mDatabase = null; } else { // 如果 mDatabase 未被 close(),则直接返回 return mDatabase; // The database is already open for business } } if (mIsInitializing) { throw new IllegalStateException("getReadableDatabase called recursively"); } try { // 注意此处,优先获取可读写的数据库 return getWritableDatabase(); } catch (SQLiteException e) { if (mName == null) throw e; // Can't open a temp database read-only! Log.e(TAG, "Couldn't open " + mName + " for writing (will try read-only):", e); } SQLiteDatabase db = null; try { mIsInitializing = true; String path = mContext.getDatabasePath(mName).getPath(); /** * 层层跟进,最终: * db = new SQLiteDatabase(path, factory, flags, errorHandler, connectionNum) * 注意此处的 SQLiteDatabase.OPEN_READONLY, 即只读模式 */ db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY, mErrorHandler); if (db.getVersion() != mNewVersion) { throw new SQLiteException("Can't upgrade read-only database from version " + db.getVersion() + " to " + mNewVersion + ": " + path); } // 该方法为空实现 onOpen(db); Log.w(TAG, "Opened " + mName + " in read-only mode"); mDatabase = db; return mDatabase; } finally { mIsInitializing = false; if (db != null && db != mDatabase){ db.close(); } } }

你可能感兴趣的:(Sqlite 源码分析 -- SQLiteOpenHelper (API 14))