編輯:關於Android編程
最近項目需要用到涉及數據庫SQLite的知識,真正用的時候才發現自己一點都不熟悉。所以打算將其使用方法總結一下,方便自己以後復習。
SQLiteDatabase類中提供了5 個static方法用來打開一個文件對應的數據庫。
//openDatabase方法打開path文件對應的數據庫。 public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,DatabaseErrorHandler errorHandler) //openOrCreateDatabase 如果不存在則先創建再打開數據庫,如果存在則直接打開。 public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory,DatabaseErrorHandler errorHandler)
//創建打開數據庫。 SQLiteDatabase mTestDb = SQLiteDatabase.openOrCreateDatabase("/data/data/cn.vn.sqlitedatademo/databases/my.db", null);要保證文件路徑是已存在,(例如沒有databases文件夾,則會報錯android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database)
Activity的父類(不是直接父類)ContextWrapper.java實現了context.java中的如下兩個抽象方法:
SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory)
SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
DatabaseErrorHandler errorHandler)
所以可以在Activity中直接調用這兩個方法來創建數據庫,或者通過它的context來創建數據庫。
創建一張表,表名user_info,列為 _id(主鍵並且自動增加)、name(用戶名)、pwd(密碼)、modifyTime(修改時間)。
mTestDb.execSQL("CREATE TABLE IF NOT EXISTS user_info(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT,pwd TEXT,modifyTime INTEGER)");
public static void InsertTest(){ UserBean user = new UserBean(); user.setName("xiaopihai"); user.setPwd("12345678"); user.setModifyTime(System.currentTimeMillis()); //增加一條數據,INSERT INTO user_info VALUES()因為有4列,所以需要寫4項數據,否則會失敗, //第一個數據位null,這是因為它是自動增長的。. mTestDb.execSQL("INSERT INTO user_info VALUES(null,'xiaopihai','12345678',"+user.getModifyTime()+")"); //不可以為主鍵設置數據,因為它是唯一的,不可以與別的相同。否則會報錯 //SQLiteConstraintException: PRIMARY KEY must be unique (code 19) //mTestDb.execSQL("INSERT INTO user_info VALUES(12,'zhangsan','mima1111',"+System.currentTimeMillis()+")"); //下面是增加一條數據(只設置某個或某幾個內容),默認沒添加的數據時空的。 mTestDb.execSQL("INSERT INTO user_info(name,pwd) VALUES('lisi','mimajjjj')"); mTestDb.execSQL("INSERT INTO user_info VALUES(null,?,?,?)",new Object[]{user.getName(),user.getPwd(),user.getModifyTime()}); mTestDb.execSQL("INSERT INTO user_info(name,pwd) VALUES(?,?)",new Object[]{"lisi","mimajjjj"}); ContentValues values = new ContentValues(); values.put(UserSQLiteOpenHelper.COL_NAME,"qwerdf"); //values.put(UserSQLiteOpenHelper.COL_PWD, "qwerdflol"); values.put(UserSQLiteOpenHelper.COL_TIME, user.getModifyTime()); mTestDb.insert("user_info", null,values); }
數據庫結果
_id|name|pwd|modifyTime 1|xiaopihai|12345678|1466403447668 2|lisi|mimajjjj| 3|xiaopihai|12345678|1466403447668 4|lisi|mimajjjj| 5|qwerdf||1466403447668
數據庫增加有兩種方法:
(一)通過執行sql語句,調用execSQL(String sql) 或者 execSQL(String sql,Object[] bindArgs)方法。
execSQL(String sql) 執行不帶占位符的sql語句
mTestDb.execSQL("INSERT INTO user_info(name,pwd) VALUES('hhohh', 'hidiiiihiihh')");
execSQL(String sql, Object[] bindArgs)執行帶占位符的SQL語句。
mTestDb.execSQL("INSERT INTO user_info(name,pwd) VALUES(?,?)",new Object[]{"lisi","mimajjjj"});
(二)SQLiteDatabase的insert(String table,String nullColumnHack,ContentValuesvalues)方法,
參數1表名稱,
參數2空列的默認值
參數3ContentValues類型的一個封裝了列名稱和列值的Map;
返回值:新插入的行的行號,或-1(如果發生錯誤)。
values中可以存單個或多個數據。
ContentValues values = new ContentValues(); values.put(UserSQLiteOpenHelper.COL_NAME,"qwerdf"); //values.put(UserSQLiteOpenHelper.COL_PWD, "qwerdflol"); values.put(UserSQLiteOpenHelper.COL_TIME, user.getModifyTime()); mTestDb.insert("user_info", null,values);}
public static void updateTest(){ mTestDb.execSQL("UPDATE user_info SET name = 'update1' WHERE _id = 1;"); mTestDb.execSQL("UPDATE user_info SET name =? WHERE _id=?",new Object[]{"update1",1}); mTestDb.execSQL("UPDATE user_info SET name = 'update2',modifyTime=111 WHERE _id = 2;"); mTestDb.execSQL("UPDATE user_info SET name =? ,modifyTime =? WHERE _id=?",new Object[]{"update1",111,2}); ContentValues values = new ContentValues(); values.put("name","update3"); values.put("pwd", "2222222"); values.put("modifyTime", 898); mTestDb.update("user_info", values, "_id=?", new String[]{String.valueOf(3)}); }結果:
_id|name|pwd|modifyTime 1|update1|12345678|1466404010484 2|update1|mimajjjj|111 3|update3|2222222|898 4|lisi|mimajjjj| 5|qwerdf||1466404010484
修改數據庫兩種方法:
(一)通過execSQL執行sql語句。
(二)通過方法
在數據庫中更新行的便捷方法。
參數:
更新的表名
map更新的內容。null是有效值將被轉換為NULL。
whereClause可選更新時WHERE子句適用。傳遞null將更新所有行。
返回
受影響的行數,如果沒有返回0。
public static void deleteTest(){ mTestDb.execSQL("delete from user_info where _id=1"); //mTestDb.execSQL("delete from user_info where _id=?",new Object[]{1}); mTestDb.delete("user_info", "_id=?", new String[]{String.valueOf(2)}); }結果:
_id|name|pwd|modifyTime 3|update3|2222222|898 4|lisi|mimajjjj| 5|qwerdf||1466404010484
刪除數據庫的兩種方法:
修改數據庫兩種方法:
(一)通過execSQL執行sql語句。
(二)通過下面方法
public ListfindAll() { List userList = new ArrayList (); //查詢表中的所有數據。 Cursor cursor = mDB.query(UserSQLiteOpenHelper.DATABASE_TABLE_USER, null, null, null, null, null, UserSQLiteOpenHelper.COL_TIME + " desc"); //order by modifytime 降序 if (null != cursor) { while (cursor.moveToNext()) { UserBean user = new UserBean(); user.set_id(cursor.getLong(cursor .getColumnIndex(UserSQLiteOpenHelper.COL_ID))); user.setName(cursor.getString(cursor .getColumnIndex(UserSQLiteOpenHelper.COL_NAME))); user.setPwd(cursor.getString(cursor .getColumnIndex(UserSQLiteOpenHelper.COL_PWD))); user.setModifyTime(cursor.getLong(cursor .getColumnIndex(UserSQLiteOpenHelper.COL_TIME))); userList.add(user); } cursor.close(); } return userList; }
//某個或某些查詢 //模糊查詢 Cursor cursor = mDB.query(UserSQLiteOpenHelper.DATABASE_TABLE_USER, null, UserSQLiteOpenHelper.COL_NAME + " like?"+" and "+UserSQLiteOpenHelper.COL_ID+" >?", new String[] {"%"+name+"%",2+""}, null, null, UserSQLiteOpenHelper.COL_ID + " desc"); // Cursor cursor = mDB.query(UserSQLiteOpenHelper.DATABASE_TABLE_USER, // null, UserSQLiteOpenHelper.COL_NAME + " =?", // new String[] {name}, null, null, UserSQLiteOpenHelper.COL_ID // + " desc"); //多個條件查詢 // Cursor cursor = mDB.query(UserSQLiteOpenHelper.DATABASE_TABLE_USER, // null, UserSQLiteOpenHelper.COL_NAME + " like?"+" and "+UserSQLiteOpenHelper.COL_ID+" >?", // new String[] {"%"+name+"%",2+""}, null, null, UserSQLiteOpenHelper.COL_ID // + " desc");
這是SqliteDatabase提供的幾種方法,可以適當選用,進行查詢。
SQLiteOpenHelper
SQLiteOpenHelper類(抽象類),一個輔助類來管理數據庫的建立和版本管理。
可以創建一個它的子類,實現onCreate(SQLiteDatabase),
onUpgrade(SQLiteDatabase, int, int)以及可選的方法onOpen(SQLiteDatabase),它主要是打開數據庫(如果已存在),如果沒存在則創建並打開。根據需要進行升級。
對其子類進行初始化時UserSQLiteOpenHelper.getInstance(context),這時並沒有建立數據庫。
public static UserSQLiteOpenHelper getInstance(Context context) {
if (null == mInstance) {
mInstance = new UserSQLiteOpenHelper(context);
mContext = context;
}
return mInstance;
}
private UserSQLiteOpenHelper(Context context) {
//這時並沒有建立數據庫。
super(context, REMOTE_LIVE_DATABASE_NAME, null, version);
}
看父類SQLiteOpenHelper類源碼
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
this(context, name, factory, version, 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;
}
先是調方法SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version),然後掉到方法SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version),該方法中要求我們傳遞的version必須大於等於1,否則會報錯IllegalArgumentException異常。這個方法中並沒有為我們創建並打開數據庫,只是存了5個變量的值而已。
那什麼時候才會創建數據庫呢?
SQliteOpenHelper
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()) {
// 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();
}
}
}
查看SQLiteOpenHelper源碼中,發現只有getDatabaseLocked()中才會創建數據庫,也就是第一次調用SQLiteOpenHelper.getWritableDatabase()或SQLiteOpenHelper.getReadableDatabase()時才回真正的創建數據庫。此方法創建的數據庫地址為:/data/data/包名/databases/
onConfigure(db)
創建數據庫後,調用onConfigure(db),這個方法裡面可以設置數據庫連接的一些參數,如setLocale() 、setMaximumSize()、setForeignKeyConstraintsEnabled()。
onCreate(db)
再向下會走到onCreate(db)方法中,onCreate只在數據庫第一次創建的時候會調用,調用之前version = 0,之後就會設置新的version,所以此方法不會再走了。在onCreate()方法中,主要用來創建表。
之後使用時可以通過設置SQLiteOpenHelper 中的mNewVersion,然後調用getReadableDatabase()或getWritableDatabase(),當mNewVersion大於數據庫的version,則會調用onUpgrade來升級。而當mNewVersion小於數據庫的version,則調用onDwongrade來降級。然後再將此版本號設置為數據庫的版本號。
db.setVersion(mNewVersion)
如何設置mNewVersion呢?
查看SQLiteOpenHelper中只有構造方法中設置了mNewVersion,所有只能通過這兩個方法才可以。(子類調用父類的這兩個方法。。)
public SQLiteOpenHelper (Context context, String name, SQLiteDatabase.CursorFactory factory, int version)
public SQLiteOpenHelper (Context context, String name, SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler)
onOpen()每次打開數據庫會調用,選用,不是必須的。
demo下載鏈接:http://download.csdn.net/detail/vnanyesheshou/9581418
效果圖:
在學習獲取相冊中圖片進行裁剪的時候遇到了比較大的問題,在糾結了近半天才真的解決,下面分享一下學習經驗。問題:選擇了相冊中的圖片之後要進入圖片裁剪的時候出錯,(華為)手機提
今天在使用安卓三星S3開發時,發現數據庫老是鎖住,其他機型並未出現鎖住的問題,查看數據庫所在的文件夾發現,和db文件同名的多出了一個文件以-journal結尾的莫名其妙的
安卓驗證碼的簡單實現我們經常在登錄或者注冊的時候要求輸入驗證碼,這裡簡單介紹一下一種方法 效果如下首先是要獲取 隨機的四個字母組合,我這裡是將26個字母存儲到一個數組中,
在Google官方Android設計指南中(鏈接:http://www.apkbus.com/design/get-started/ui-overview.html)有一