2012年3月18日 星期日

說說。SQLite

今天我們來說說SQLite,小書學到兩種方法,一種是繼承SQLiteOpenHelper實作,一種是利用Java的I/O來處理(關於儲存方法,可以參考這裡,是這篇的翻譯。),分別封裝成class。

首先是利用SQLiteOpenHelper實作的class,亦或可以參考這裡


/*
 參考:
 http://www.moke.tw/wordpress/computer/advanced/249
 http://www.moke.tw/wordpress/computer/advanced/238
 http://www.moke.tw/wordpress/computer/advanced/245
 */

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class SQLite extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "moke_config.db";    //資料庫名稱
    private static final int DATABASE_VERSION = 1;    //資料庫版本

    private SQLiteDatabase db;

    public SQLite(Context context) {    //建構子
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        db = this.getWritableDatabase();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String DATABASE_CREATE_TABLE =
            "create table config ("
                + "_ID INTEGER PRIMARY KEY,"
                + "name TEXT,"
                + "value INTEGER"
            + ");";
        //建立config資料表,詳情請參考SQL語法
        db.execSQL(DATABASE_CREATE_TABLE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //oldVersion=舊的資料庫版本;newVersion=新的資料庫版本
        db.execSQL("DROP TABLE IF EXISTS config");    //刪除舊有的資料表
        onCreate(db);
    }
   
    // 取得所有記錄
    public Cursor getAll() {
        return db.rawQuery("SELECT * FROM table_name", null);
    }
   
    // 取得所有記錄
    public Cursor getAll() {
        return db.query("table_name",        //資料表名稱
        new String[] {"_ID", "name", "value"},    //欄位名稱
        null, // WHERE
        null, // WHERE 的參數
        null, // GROUP BY
        null, // HAVING
        null  // ORDOR BY
        );
    }
    // 取得一筆紀錄
    public Cursor get(long rowId) throws SQLException {
        Cursor cursor = db.query(true,
        "table_name",                //資料表名稱
        new String[] {"_ID", "name", "value"},    //欄位名稱
        "_ID=" + rowId,                //WHERE
        null, // WHERE 的參數
        null, // GROUP BY
        null, // HAVING
        null, // ORDOR BY
        null  // 限制回傳的rows數量
        );

        // 注意:不寫會出錯
        if (cursor != null) {
            cursor.moveToFirst();    //將指標移到第一筆資料
        }
        return cursor;
    }
   
    //新增一筆記錄,成功回傳rowID,失敗回傳-1
    public long create(String name, String value) {
        ContentValues args = new ContentValues();
        args.put("name", name);
        args.put("value", value);

        return db.insert("table_name", null, args);
    }
   
    //修改記錄,回傳成功修改筆數
    public int update(long rowId, String value) {
        ContentValues args = new ContentValues();
        args.put("value", value);

        return db.update("table_name",    //資料表名稱
        args,                //VALUE
        "_ID=" + rowId,            //WHERE
        null                //WHERE的參數
        );
    }
}




會覺得怪怪的嗎?
沒錯,這個class沒有辦法把SQLite放到SD卡中,該怎麼做呢?目前已知有兩解,如果還有錯請指正。
  1. 將apk設定安裝在SD卡中。4/2後來發現沒這回事:
    可以直接在上述的那個class中,將DATABASE_NAME改為:
    static final String DATABASE = android.os.Environment
        .getExternalStorageDirectory().getAbsolutePath() +"/檔案名稱.db3";
    
    就可以啦!哈哈!有關確定手機是否有安裝SD卡,參考這裡
  2. 或是參考下面的code,用它來取代我們之前繼承的 SQLiteOpenHelper :


import java.io.File;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;

/**
 * A helper class to manage database creation and version management.
 * You create a subclass implementing {@link #onCreate}, {@link #onUpgrade} and
 * optionally {@link #onOpen}, and this class takes care of opening the database
 * if it exists, creating it if it does not, and upgrading it as necessary.
 * Transactions are used to make sure the database is always in a sensible state.
 * <p>For an example, see the NotePadProvider class in the NotePad sample application,
 * in the <em>samples/</em> directory of the SDK.</p>
 */
public abstract class SDSQLiteOpenHelper {
    private static final String TAG = SDSQLiteOpenHelper.class.getSimpleName();

    private final Context mContext;
    private final String mName;
    private final CursorFactory mFactory;
    private final int mNewVersion;

    private SQLiteDatabase mDatabase = null;
    private boolean mIsInitializing = false;

    /**
     * Create a helper object to create, open, and/or manage a database.
     * 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
     */
    public SDSQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
        if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);

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

    /**
     * Create and/or open a database that will be used for reading and writing.
     * 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 it.
     *
     * <p>Errors such as bad permissions or a full disk may cause this operation
     * to fail, but future attempts may succeed if the problem is fixed.</p>
     *
     * @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 && 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;
        try {
            mIsInitializing = true;
            if (mName == null) {
                db = SQLiteDatabase.create(null);
            } else {
                    String path = getDatabasePath(mName).getPath();
                db = SQLiteDatabase.DatabopenOrCreatease(path, 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 = db;
            } else {
                if (db != null) db.close();
            }
        }
    }

    /**
     * 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.
     *
     * @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 && mDatabase.isOpen()) {
            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 = getDatabasePath(mName).getPath();
            db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READWRITE);
            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();
        }
    }

    /**
     * Close any open database object.
     */
    public synchronized void close() {
        if (mIsInitializing) throw new IllegalStateException("Closed during initialization");

        if (mDatabase != null && mDatabase.isOpen()) {
            mDatabase.close();
            mDatabase = null;
        }
    }
 
    public File getDatabasePath(String name)
    {
            return new File("/sdcard/" + name);
    }

    /**
     * Called when the database is created for the first time. This is where the
     * creation of tables and the initial population of the tables should happen.
     *
     * @param db The database.
     */
    public abstract void onCreate(SQLiteDatabase db);

    /**
     * Called when the database needs to be upgraded. The implementation
     * should use this method to drop tables, add tables, or do anything else it
     * needs to upgrade to the new schema version.
     *
     * <p>The SQLite ALTER TABLE documentation can be found
     * <a href="http://sqlite.org/lang_altertable.html">here</a>. If you add new columns
     * you can use ALTER TABLE to insert them into a live table. If you rename or remove columns
     * you can use ALTER TABLE to rename the old table, then create the new table and then
     * populate the new table with the contents of the old table.
     *
     * @param db The database.
     * @param oldVersion The old database version.
     * @param newVersion The new database version.
     */
    public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);

    /**
     * Called when the database has been opened.
     * Override method should check {@link SQLiteDatabase#isReadOnly} before
     * updating the database.
     *
     * @param db The database.
     */
    public void onOpen(SQLiteDatabase db) {}
}


然而,說回頭的第二種方法,就是先在assets中建立一個空的.db3檔,然後
對它進行存取操作,注意裡面的context.getAssets().open(DATABASE_FILENAME)方法,
它便是獲取assets之中的檔案,複製到SD卡之中的資料夾(如果沒有則創建):


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

public class DataBasePlus {

    private static final String TAG = "DatabasePlus";//做Log用
    private SQLiteDatabase db;

    /** {"column1","colume2","column3"} */
    public static final String[] COLUMN_LIST = { "column1","colume2","column3" };//欄位的列表

    private final String DATABASE_TABLE = "table";//table,如果有需要做兩個以上的table,可增加成為array

    public static final String DATABASE_PATH = android.os.Environment
            .getExternalStorageDirectory().getAbsolutePath() + "/Doubt";//路徑,標示了到SD卡資料夾的絕對路徑

    public static final String DATABASE_NAME = "GiRu.db3";//database的檔案名稱

    private Context context;

    public DataBasePlus(Context context) {

        this.context = context;
        Log.d(TAG, "public DataBaseTwins().");
    }
    /**開啟SQLite使用*/
    public synchronized boolean openSQLite() {
        if (isDataBaseOpen()) {
            Log.d(TAG, "it's already open.");
            return false;
        }
        db = openDatabase(DATABASE_NAME);

        Log.d(TAG, "database is not open!.");
        return true;
    }

    private SQLiteDatabase openDatabase(String DATABASE_FILENAME) {

        String databaseFilename;

        databaseFilename = DATABASE_PATH + "/" + DATABASE_FILENAME;
        File dir = new File(DATABASE_PATH);
        if (!dir.exists()) {
            Log.d(TAG, "file of dir is not exists.");
            dir.mkdir();
        }
        if ((!(new File(databaseFilename)).exists())) {
            Log.d(TAG, "SQlite is not exists.");
            InputStream is;
            FileOutputStream fos;
            try {
                Log.d(TAG, "context.getAssets().open(DATABASE_FILENAME);.");
                is = context.getAssets().open(DATABASE_FILENAME);
                Log.d(TAG, "new FileOutputStream(databaseFilename).");
                fos = new FileOutputStream(databaseFilename);
                byte[] buffer = new byte[1024];
                int count = 0;

                while ((count = is.read(buffer)) > 0) {
                    Log.d(TAG, "write..");
                    fos.write(buffer, 0, count);
                }
                Log.d(TAG, "close().");
                fos.close();
                is.close();
            } catch (IOException e) {
                Log.e(TAG, "fail for IOException.");
                e.printStackTrace();
            }

        } else {

            Log.d(TAG, "SQlte is already exists.");

        }
        db = SQLiteDatabase.openOrCreateDatabase(databaseFilename, null);

        return db;
    }
 
    public synchronized boolean add(ContentValues cv) {
        Log.d(TAG, "add()");
        if (isDataBaseOpen()) {
            Log.d(TAG, "DataBase is open.");
            return db.insert(DATABASE_TABLE, null, cv) > 0;
        }
        return false;
    }

 
    public synchronized Cursor quary(String column, String term) {
        Cursor cursor = null;
        if (isDataBaseOpen()) {

            cursor = db.query(this.DATABASE_TABLE, DataBasePlus.COLUMN_LIST,
                    column + "=?", new String[] { term }, null, null, null);
            if (cursor.getCount() > 0) {
                cursor.moveToFirst();
            }

        }
        return cursor;
    }

    public synchronized Cursor quaryAll() {
        Cursor cursor = null;
        if (isDataBaseOpen()) {
            cursor = db.query(this.DATABASE_TABLE, DataBasePlus.COLUMN_LIST,
                    null, null, null, null, null);
            if (cursor.getCount() > 0) {
                cursor.moveToFirst();
            }

        }
        return cursor;
    }

    public synchronized boolean close() throws SQLException {
        if (isDataBaseOpen()) {
            db.close();
            Log.d(TAG, "db.close()");
            return true;
        }
        return false;
    }

    public synchronized boolean clearAll() {
        Log.d(TAG, "clearAll()");
        if (isDataBaseOpen()) {
            try {
                Log.d(TAG, "clearAll(),isOpen, prepare to clear");
                return db.delete(DATABASE_TABLE, null, null) > 0;
            } catch (SQLException e) {
                Log.e(TAG, "fail for SQLException.");
            }
        }

        Log.d(TAG, "database is not open.");

        return false;
    }

    public synchronized boolean isDataBaseOpen() throws SQLException {
        if ((db == null) || (!db.isOpen())) {
            return false;
        }
        return true;
    }
}


然後,老師有說過,可以學SQL語句,再利用.execSQL()來代替android裡面的調用方法。
有關SQL語句可以參考這個或是這個

最後附上原本的SQLiteOpenHelper.class:


/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.database.sqlite;

import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.DefaultDatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;

/**
 * A helper class to manage database creation and version management.
 *
 * <p>You create a subclass implementing {@link #onCreate}, {@link #onUpgrade} and
 * optionally {@link #onOpen}, and this class takes care of opening the database
 * if it exists, creating it if it does not, and upgrading it as necessary.
 * Transactions are used to make sure the database is always in a sensible state.
 *
 * <p>This class makes it easy for {@link android.content.ContentProvider}
 * implementations to defer opening and upgrading the database until first use,
 * to avoid blocking application startup with long-running database upgrades.
 *
 * <p>For an example, see the NotePadProvider class in the NotePad sample application,
 * in the <em>samples/</em> directory of the SDK.</p>
 *
 * <p class="note"><strong>Note:</strong> this class assumes
 * monotonically increasing version numbers for upgrades.</p>
 */
public abstract class SQLiteOpenHelper {
    private static final String TAG = SQLiteOpenHelper.class.getSimpleName();

    private final Context mContext;
    private final String mName;
    private final CursorFactory mFactory;
    private final int mNewVersion;

    private SQLiteDatabase mDatabase = null;
    private boolean mIsInitializing = false;
    private final DatabaseErrorHandler mErrorHandler;

    /**
     * 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());
    }

    /**
     * Create a helper object to create, open, and/or manage a database.
     * The database is not actually created or opened until one of
     * {@link #getWritableDatabase} or {@link #getReadableDatabase} is called.
     *
     * <p>Accepts input param: a concrete instance of {@link DatabaseErrorHandler} to be
     * used to handle corruption when sqlite reports database corruption.</p>
     *
     * @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
     * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
     * corruption.
     */
    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;
    }

    /**
     * Return the name of the SQLite database being opened, as given tp
     * the constructor.
     */
    public String getDatabaseName() {
        return mName;
    }

    /**
     * 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.
     *
     * <p>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.</p>
     *
     * <p class="caution">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()) {
                // darn! the user closed the database by calling mDatabase.close()
                mDatabase = null;
            } else if (!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, mErrorHandler);
            }

            int version = db.getVersion();
            if (version != mNewVersion) {
                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);
            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();
            }
        }
    }

    /**
     * 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.
     *
     * <p class="caution">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 = null;
            } else {
                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 = 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();
        }
    }

    /**
     * Close any open database object.
     */
    public synchronized void close() {
        if (mIsInitializing) throw new IllegalStateException("Closed during initialization");

        if (mDatabase != null && mDatabase.isOpen()) {
            mDatabase.close();
            mDatabase = null;
        }
    }

    /**
     * Called when the database is created for the first time. This is where the
     * creation of tables and the initial population of the tables should happen.
     *
     * @param db The database.
     */
    public abstract void onCreate(SQLiteDatabase db);

    /**
     * Called when the database needs to be upgraded. The implementation
     * should use this method to drop tables, add tables, or do anything else it
     * needs to upgrade to the new schema version.
     *
     * <p>The SQLite ALTER TABLE documentation can be found
     * <a href="http://sqlite.org/lang_altertable.html">here</a>. If you add new columns
     * you can use ALTER TABLE to insert them into a live table. If you rename or remove columns
     * you can use ALTER TABLE to rename the old table, then create the new table and then
     * populate the new table with the contents of the old table.
     *
     * @param db The database.
     * @param oldVersion The old database version.
     * @param newVersion The new database version.
     */
    public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);

    /**
     * Called when the database needs to be downgraded. This is stricly similar to
     * onUpgrade() method, but is called whenever current version is newer than requested one.
     * However, this method is not abstract, so it is not mandatory for a customer to
     * implement it. If not overridden, default implementation will reject downgrade and
     * throws SQLiteException
     *
     * @param db The database.
     * @param oldVersion The old database version.
     * @param newVersion The new database version.
     */
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        throw new SQLiteException("Can't downgrade database from version " +
                oldVersion + " to " + newVersion);
    }

    /**
     * Called when the database has been opened.  The implementation
     * should check {@link SQLiteDatabase#isReadOnly} before updating the
     * database.
     *
     * @param db The database.
     */
    public void onOpen(SQLiteDatabase db) {}
}


最後注意別忘記加上權限呀!

沒有留言:

張貼留言

你好,我是小書,如果文章內容有錯誤,或是看到有建議以及任何感想時,歡迎提出分享,我們一起學習一起努力。

追蹤者