天天看點

梳理SQLiteDatabase、openOrCreateDatabase、context、SQLiteOpenHelper

 梳理SQLiteDatabase、openOrCreateDatabase、SQLiteOpenHelper

                    據我所知,android建立資料庫可以通過以下方法:

一、 SQLiteDatabase.openOrCreateDatabase(file, factory):(以下都在這個SQLiteDatabase類中)

                         1. 一個類名+方法就是個static方法:

                            public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) {

                                      return openOrCreateDatabase(file.getPath(), factory);

                             }

                         2. 換了絕對路徑。

                             public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) {

                                    return openDatabase(path, factory, CREATE_IF_NECESSARY);

                             }

                         3.去調用了openDatabase方法。

                                      public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {

                                              SQLiteDatabase db = null;

                                              try {

                                                  // Open the database.

                                                  return new SQLiteDatabase(path, factory, flags);

                                              } catch (SQLiteDatabaseCorruptException e) {

                                                  // Try to recover from this, if we can.

                                                  // TODO: should we do this for other open failures?

                                                  Log.e(TAG, "Deleting and re-creating corrupt database " + path, e);

                                                  EventLog.writeEvent(EVENT_DB_CORRUPT, path);

                                                  new File(path).delete();

                                                  return new SQLiteDatabase(path, factory, flags);

                                              }

                                          }

                         4. 關鍵的就這行代碼:return new SQLiteDatabase(path, factory, flags);其他的是異常處理。

                            也就是建立了這個類,我們建立資料庫也可以這樣直接new出來。

                         5.現在關鍵的工作就落在SQLiteDatabase這個類的構造函數上了。  

    private SQLiteDatabase(String path, CursorFactory factory, int flags) {

        if (path == null) {

            throw new IllegalArgumentException("path should not be null");

        }

        mFlags = flags;

        mPath = path;

        mLogStats = "1".equals(android.os.SystemProperties.get("db.logstats"));

        mSlowQueryThreshold = SystemProperties.getInt(LOG_SLOW_QUERIES_PROPERTY, -1);

        mLeakedException = new IllegalStateException(path +

            " SQLiteDatabase created and never closed");

        mFactory = factory;

        dbopen(mPath, mFlags);   <-----------------------------------------------------------

        mPrograms = new WeakHashMap<SQLiteClosable,Object>();

        try {

            setLocale(Locale.getDefault());

        } catch (RuntimeException e) {

            Log.e(TAG, "Failed to setLocale() when constructing, closing the database", e);

            dbclose();

            throw e;

        }

    }

                   6.起關鍵的就是 dbopen(mPath, mFlags);

                           private native void dbopen(String path, int flags);

                   7.看到這個native,就是jni咯!往下就是c++了。其中細體什麼實作open或create就不用管了。感興趣可以往下跟。

 二、context.openOrCreateDatabase(name, mode, factory);

                                     1、看android幫助是這樣描述的:

                                      Open a new private SQLiteDatabase associated with this Context's application package.

                                      Create the database file if it doesn't exist.

                                      2 、看源碼沒發現細體的實作部分的代碼,發現的話分享一下給我。搜了很多源碼,隻有這樣:

                                           context.java中: 

                                           public abstract SQLiteDatabase openOrCreateDatabase(String name,int mode, CursorFactory factory);

                                           是個抽象方法,其子類ContextWrapper.java:

                                           public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {

                                                         return mBase.openOrCreateDatabase(name, mode, factory);

                                          }

                                          又沒見哪個子類去覆寫這個方法;

         小結:查網上一些資料也是說第二種通過context的方法,其實最終也是得通過SQLiteDatabase這個類中的方法。

                      我認為也是,因為1.context中也用到SQLiteDatabase 這個類啊,可以直接調用這個SQLiteDatabase 的方法嘛。

                                                      2.我們知道在data/data+加上這個應用的包名,就是這個應用程式存放私有資料的目錄。那麼這個應用程式

                                                       隻要通過資料庫名稱就能找到其路徑。而這個SQLiteDatabase的 openOrCreateDatabase(File file, CursorFactory factory)

                                                       再到openOrCreateDatabase(String path, CursorFactory factory);由此可猜這個openOrCreateDatabase(file...)應該是提供

                                                       給context的。

       (三) 剩下就是這個SQLiteOpenHelper

                        1. 都說這個SQLiteOpenHelper.java類是友善操作資料庫的類。

                        2. 那分析一下源碼

                                        public abstract class SQLiteOpenHelper

                         3.是以通常我們要使用個類就得去繼承它。并去實作父類的抽象方法如:

                                        public class DatabaseHelper extends SQLiteOpenHelper

                                        {

                                         public DatabaseHelper(Context context, String name, CursorFactory cursorFactory, int version)

                                         {

                                          super(context, name, cursorFactory, version);

                                         }

                                         @Override

                                         public void onCreate(SQLiteDatabase db)

                                         {  

                                         }

                                         @Override

                                         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)

                                         {  

                                         }

                                         @Override

                                         public void onOpen(SQLiteDatabase db)

                                         {

                                          super.onOpen(db);

                                         }

                                        }

                         4. 好像就這麼簡單,其實什麼也沒做。那什麼建立或打開資料庫?

                         5.重要的是SQLiteOpenHelper中的getWritableDatabase和getReadableDatabase方法,你會發現getReadableDatabase中調用了getWritableDatabase

                         6.是以隻要getWritableDatabase清楚getWritableDatabase是如何實作的,就很明朗了。

                                                                                                                                       看似複雜,  慢慢往下看,還有注釋(同時要清楚這方法目的就是要建立或打開資料庫)

 public synchronized SQLiteDatabase getWritableDatabase() {

        if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {

            return mDatabase;  // The database is already open for business                  //如果已經打開了,直接傳回。

        }

        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 = mContext.openOrCreateDatabase(mName, 0, mFactory);                    //關鍵是這行代碼,是不是很熟悉

            }

            int version = db.getVersion();

            if (version != mNewVersion) {

                db.beginTransaction();

                try {

                    if (version == 0) {

                           onCreate(db);  //子類我們實作的方法(其實什麼也沒做,要想這第一次建立時做一些操作,

                                                     //就自己在子類的方法實作,如建立表)                                                                            

                    } else {

                        onUpgrade(db, version, mNewVersion);  //子類我們實作的方法(版本發生變化)

                    }

                    db.setVersion(mNewVersion);

                    db.setTransactionSuccessful();

                } finally {

                    db.endTransaction();

                }

            }

            onOpen(db);                                    //子類我們實作的方法                                            

            success = true;

            return db;

        } finally {

            mIsInitializing = false;

            if (success) {

                if (mDatabase != null) {

                    try { mDatabase.close(); } catch (Exception e) { }

                    mDatabase.unlock();

                }

                mDatabase = db;

            } else {

                if (mDatabase != null) mDatabase.unlock();

                if (db != null) db.close();

            }

        }

    }