Android SQLiteOpenHelper使用和源码详解

来源:互联网 发布:恒泰实达程序员怎么样 编辑:程序博客网 时间:2024/04/30 16:08

SQLiteOpenHelper

在讲解闹钟数据库之前,需要先来分析一下SQLiteOpenHelper的源码,从而了解SQLite数据库的使用.

使用方法

大家在使用SQLiteOpenHelper的时候,一般习惯使用如下代码构建一个自定义的SQLiteOpenHelper:

public class TestDBHelper extends SQLiteOpenHelper {    public static final int DATABASE_VERSION = 1;    public static final String DATABASE_NAME = "test.db";    private static final String SQL_CREATE_TEST_TABLE = "CREATE TABLE " + TestTable.TABLE_NAME +            " (" +            TestTable._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +            TestTable.COLUMN_NAME_TEST_NAME + " TEXT, " +            TestTable.COLUMN_NAME_TEST_TIME_YEAR + " INTEGER, " +            TestTable.COLUMN_NAME_TEST_TIME_MONTH + " INTEGER, " +            TestTable.COLUMN_NAME_TEST_TIME_DAY + " INTEGER, " +            " )";    private static final String SQL_DELETE_TEST_TABLE = "DROP TABLE IF EXISTS " +            TestTable.TABLE_NAME;    private static TestDBHelper mInstance;    private SQLiteDatabase rdb;    private SQLiteDatabase wdb;    private TestDBHelper(Context context) {        super(context, DATABASE_NAME, null, DATABASE_VERSION);        wdb = mInstance.getWritableDatabase();        rdb = mInstance.getReadableDatabase();    }    public TestDBHelper getInstance(Context context) {        if (mInstance == null) {            synchronized (TestDBHelper.class) {                if (mInstance == null) {                    mInstance = new TestDBHelper(context);                }            }        }        return mInstance;    }    @Override    public void onCreate(SQLiteDatabase db) {        db.execSQL(SQL_CREATE_TEST_TABLE);    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        db.execSQL(SQL_DELETE_TEST_TABLE);        onCreate(db);    }    public class TestTable implements BaseColumns {        public static final String TABLE_NAME = "test";        public static final String COLUMN_NAME_TEST_NAME = "TEST_name";        public static final String COLUMN_NAME_TEST_TIME_YEAR = "TEST_year";        public static final String COLUMN_NAME_TEST_TIME_MONTH = "TEST_month";        public static final String COLUMN_NAME_TEST_TIME_DAY = "TEST_day";    }}

调用时:

TestDBHelper dbHelper = TestDBHelper.getInstance(context);

但是,通过上述代码,我们是没法确定onCreate函数和onUpgrade函数的调用时机.


SQLiteOpenHelper源码

中文注释源码如下:

public abstract class SQLiteOpenHelper {    /**     * 为true时,当数据库句柄已经打开,返回read-only句柄.     */    private static final boolean DEBUG_STRICT_READONLY = false;    private final Context mContext;    /**     * 数据库文件名称.     */    private final String mName;    private final CursorFactory mFactory;    /**     * 数据库版本号.     */    private final int mNewVersion;    private final DatabaseErrorHandler mErrorHandler;    /**     * 数据库句柄.     */    private SQLiteDatabase mDatabase;    /**     * 数据库打开进行时标记.     */    private boolean mIsInitializing;    /**     * SQLiteOpenHelper的构造函数,用来创建,打开,操作SQLite数据库.     * 这个方法会被很快返回.因为这个方法只是参数赋值,并没有真正的创建SQLite数据库.     * 只有当getWritableDatabase或者getReadableDatabase被调用时,SQLite数据库才会被真正的创建或打开.     *     * @param context      进程上下文     * @param name         文件系统存储的数据库文件名称     * @param factory      to use for creating cursor objects, or null for the default     * @param version      数据库版本号,初始版本为1     * @param errorHandler 处理Sqlite异常类,默认为null.     */    public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,                            DatabaseErrorHandler errorHandler) {        if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);        mContext = context;        mName = name;        mFactory = factory;        mNewVersion = version;        mErrorHandler = errorHandler;    }    /**     * 返回数据库文件名称     */    public String getDatabaseName() {        return mName;    }    /**     * 创建可读可写的数据库句柄.这个函数第一次调用时,会调用onCreate方法或者onUpgrade方法.     */    public SQLiteDatabase getWritableDatabase() {        synchronized (this) {            return getDatabaseLocked(true);        }    }    /**     * 创建只读数据库句柄.     */    public SQLiteDatabase getReadableDatabase() {        synchronized (this) {            return getDatabaseLocked(false);        }    }    private SQLiteDatabase getDatabaseLocked(boolean writable) {        if (mDatabase != null) {            if (!mDatabase.isOpen()) {                // 说明用户手动调用close方法将mDatabase关闭了,需要重启打开                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,结束时置为false.            mIsInitializing = true;            if (db != null) {                if (writable && db.isReadOnly()) {                    db.reopenReadWrite();                }            } else if (mName == null) {                db = SQLiteDatabase.create(null);            } else {                // mName不存在则创建数据库文件.                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, 0, mFactory, mErrorHandler);                    }                } catch (SQLiteException ex) {                    if (writable) {                        throw ex;                    }                    final String path = mContext.getDatabasePath(mName).getPath();                    db = SQLiteDatabase.openDatabase(path, mFactory,                            SQLiteDatabase.OPEN_READONLY, mErrorHandler);                }            }            // 获取当前数据库版本号,第一次创建版本号为0            final int version = db.getVersion();            // 版本号不一致,则进行onCreate或者onUpgrade操作.            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方法                        onCreate(db);                    } else {                        if (version > mNewVersion) {                            // 数据库版本大于当前版本,执行降级操作                            onDowngrade(db, version, mNewVersion);                        } else {                            // 数据库版本小于当前版本,执行升级操作                            onUpgrade(db, version, mNewVersion);                        }                    }                    db.setVersion(mNewVersion);                    db.setTransactionSuccessful();                } finally {                    db.endTransaction();                }            }            mDatabase = db;            return db;        } finally {            mIsInitializing = false;            if (db != null && db != mDatabase) {                db.close();            }        }    }    /**     * 关闭数据库句柄.     */    public synchronized void close() {        if (mIsInitializing) throw new IllegalStateException("Closed during initialization");        if (mDatabase != null && mDatabase.isOpen()) {            mDatabase.close();            mDatabase = null;        }    }    /**     * 创建数据库.     */    public abstract void onCreate(SQLiteDatabase db);    /**     * 数据库升级.     */    public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);    /**     * 数据库降级.     */    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {        throw new SQLiteException("Can't downgrade database from version " +                oldVersion + " to " + newVersion);    }}

调用顺序

从注释源码中可以看出,SQLiteOpenHelper实现的onCreate和onUpgrade函数并不是在构造函数中被调用的.而是当需要获取数据库句柄时,即调用getWritableDatabase或者getReadableDatabase时被调用的.

getWritableDatabase和getReadableDatabase都是对getDatabaseLocked的加锁封装.在getDatabaseLocked中,也并非每次都会调用onCreate或者onUpgrade函数,只是当之前数据库版本号和当前数据库版本号不一致时才会根据情况调用,其他情况下只是打开可读写的文件句柄而已.

1 0
原创粉丝点击