目录
1. Demo展示
2. 实现方法
2.1 定义数据库的结构
2.2 使用SQLiteHelper来创建数据库
3. 注意事项
Demo 案例:实现联系人列表功能,我们可以增加联系人,修改联系人,删除联系人,以及根据联系人的名字查询该联系人的功能,如下图所示:
app 的结构如下:(源码见 -> Android_SQLite_Learning)
package com.jere.android_sqlite_learning.model;
/**
* @author jere
*/
public class BusinessCard {
public static final String TABLE_NAME = "BusinessCard";
public static final String COLUMN_ID = "id";
public static final String COLUMN_AVATAR = "avatar";
public static final String COLUMN_NAME = "name";
public static final String COLUMN_GENDER = "gender";
public static final String COLUMN_TELEPHONE = "telephone";
public static final String COLUMN_ADDRESS = "address";
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "("
+ COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ COLUMN_NAME + " TEXT,"
+ COLUMN_GENDER + " INTEGER,"
+ COLUMN_AVATAR + " INTEGER,"
+ COLUMN_TELEPHONE + " TEXT,"
+ COLUMN_ADDRESS + " TEXT"
+ ")";
private int id;
private int avatar;
private String name;
private String telephone;
//true:male, false:female
private boolean gender;
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAvatar() {
return avatar;
}
public void setAvatar(int avatar) {
this.avatar = avatar;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean getGender() {
return gender;
}
public void setGender(boolean gender) {
this.gender = gender;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
/**
* @author jere
*/
public class DataBaseHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "business_card_db";
public DataBaseHelper(@Nullable Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(BusinessCard.CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
//drop old table if is existed
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + BusinessCard.TABLE_NAME);
//create table again
onCreate(sqLiteDatabase);
}
/**
*
* @param businessCard
* @return 返回新插入的行的ID,发生错误,插入不成功,则返回-1
*/
public long insertBusinessCard(BusinessCard businessCard) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(BusinessCard.COLUMN_AVATAR, businessCard.getGender() ? R.drawable.male_avatar_icon : R.drawable.female_avatar_icon);
values.put(BusinessCard.COLUMN_NAME, businessCard.getName());
values.put(BusinessCard.COLUMN_GENDER, businessCard.getGender() ? 1 : 0);
values.put(BusinessCard.COLUMN_TELEPHONE, businessCard.getTelephone());
values.put(BusinessCard.COLUMN_ADDRESS, businessCard.getAddress());
long id = db.insert(BusinessCard.TABLE_NAME, null, values);
db.close();
return id;
}
/**
*
* @param searchName query database by name
* @return BusinessCard
*/
public BusinessCard getBusinessCardQueryByName(String searchName) {
BusinessCard businessCard = new BusinessCard();
SQLiteDatabase db = this.getReadableDatabase();
String[] columnArray = new String[]{
BusinessCard.COLUMN_ID,
BusinessCard.COLUMN_NAME,
BusinessCard.COLUMN_GENDER,
BusinessCard.COLUMN_AVATAR,
BusinessCard.COLUMN_TELEPHONE,
BusinessCard.COLUMN_ADDRESS};
Cursor cursor = db.query(BusinessCard.TABLE_NAME,
columnArray,
BusinessCard.COLUMN_NAME + "=? ",
new String[]{searchName},
null, null, null);
if (cursor != null && cursor.moveToNext()) {
int id = cursor.getInt(cursor.getColumnIndex(BusinessCard.COLUMN_ID));
String name = cursor.getString(cursor.getColumnIndex(BusinessCard.COLUMN_NAME));
int portrait = cursor.getInt(cursor.getColumnIndex(BusinessCard.COLUMN_AVATAR));
String telephone = cursor.getString(cursor.getColumnIndex(BusinessCard.COLUMN_TELEPHONE));
String address = cursor.getString(cursor.getColumnIndex(BusinessCard.COLUMN_ADDRESS));
int gender = cursor.getInt(cursor.getColumnIndex(BusinessCard.COLUMN_GENDER));
businessCard.setId(id);
businessCard.setName(name);
businessCard.setAvatar(portrait);
businessCard.setTelephone(telephone);
businessCard.setAddress(address);
businessCard.setGender(gender == 1);
cursor.close();
return businessCard;
}
return null;
}
/**
*
* @return 读取数据库,返回一个 BusinessCard 类型的 ArrayList
*/
public ArrayList getAllBusinessCards() {
ArrayList businessCardsList = new ArrayList<>();
String selectQuery = "SELECT * FROM " + BusinessCard.TABLE_NAME
+ " ORDER BY " + BusinessCard.COLUMN_ID + " ASC";
SQLiteDatabase db = getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
if (cursor != null) {
while (cursor.moveToNext()) {
BusinessCard businessCard = new BusinessCard();
int id = cursor.getInt(cursor.getColumnIndex(BusinessCard.COLUMN_ID));
String name = cursor.getString(cursor.getColumnIndex(BusinessCard.COLUMN_NAME));
int portrait = cursor.getInt(cursor.getColumnIndex(BusinessCard.COLUMN_AVATAR));
String telephone = cursor.getString(cursor.getColumnIndex(BusinessCard.COLUMN_TELEPHONE));
String address = cursor.getString(cursor.getColumnIndex(BusinessCard.COLUMN_ADDRESS));
int gender = cursor.getInt(cursor.getColumnIndex(BusinessCard.COLUMN_GENDER));
businessCard.setId(id);
businessCard.setName(name);
businessCard.setAvatar(portrait);
businessCard.setTelephone(telephone);
businessCard.setAddress(address);
businessCard.setGender(gender == 1);
businessCardsList.add(businessCard);
}
}
db.close();
return businessCardsList;
}
/**
*
* @return 返回数据库行数
*/
public int getBusinessCardCount() {
String countQuery = "SELECT * FROM " + BusinessCard.TABLE_NAME;
SQLiteDatabase db = getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
int count = cursor.getCount();
cursor.close();
return count;
}
/**
*
* @param id update row id (需要更新的ID)
* @param businessCard update value (去更新数据库的内容)
* @return the number of rows affected (影响到的行数,如果没更新成功,返回0。所以当return 0时,需要告诉用户更新不成功)
*/
public int updateBusinessCard(int id, BusinessCard businessCard) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put(BusinessCard.COLUMN_AVATAR, businessCard.getAvatar());
values.put(BusinessCard.COLUMN_NAME, businessCard.getName());
values.put(BusinessCard.COLUMN_TELEPHONE, businessCard.getTelephone());
values.put(BusinessCard.COLUMN_ADDRESS, businessCard.getAddress());
values.put(BusinessCard.COLUMN_GENDER, businessCard.getGender() ? 1 : 0);
int idReturnByUpdate = db.update(BusinessCard.TABLE_NAME, values, BusinessCard.COLUMN_ID + " =? ", new String[]{String.valueOf(id)});
db.close();
return idReturnByUpdate;
}
/**
*
* @param id the database table row id need to delete(需要删除的数据库表中行的ID)
* @return 返回影响到的行数,如果在 whereClause 有传入条件,返回该条件下影响到的行数,否则返回0。
* 想要删除所有行,只要在 whereClause 传入 String "1",并返回删除掉的行数总数(比如:删除了四行就返回4)
*/
public int deleteBusinessCard(int id) {
SQLiteDatabase db = getWritableDatabase();
int idReturnByDelete = db.delete(BusinessCard.TABLE_NAME, BusinessCard.COLUMN_ID + "=? ", new String[]{String.valueOf(id)});
db.close();
return idReturnByDelete;
}
/**
* 删除所有行,whereClause 传入 String "1"
* @return 返回删除掉的行数总数(比如:删除了四行就返回4)
*/
public int deleteAllBusinessCard() {
SQLiteDatabase db = getWritableDatabase();
int idReturnByDelete = db.delete(BusinessCard.TABLE_NAME, String.valueOf(1), null);
db.close();
return idReturnByDelete;
}
}
在上方的 Demo 中 onUpgrade() 方法中我们可以发现,当数据库升级时我们采用了最简单粗暴的方法,删除重建表,但在实际开发中需要严谨的对待数据库migration,一旦造成用户数据丢失,将是很差的用户体验。
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
/**在很多Demo中为了简单,直接删除重建表
//drop old table if is existed
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + BusinessCard.TABLE_NAME);
//create table again
onCreate(sqLiteDatabase); **/
//但在实际开发中需要严谨的对待数据库migration,一旦造成用户数据丢失,是很差的用户体验。
if (oldVersion < 2) {
upgradeVersion2(sqLiteDatabase);
}
}
private void upgradeVersion2(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + BusinessCard.TABLE_NAME + " ADD COLUMN " + BusinessCard.COLUMN_COMMENT + " TEXT");
}
/** 而且实际开发中,要面对着很多的升级,从1升到2,然后2到3,3到4. **/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 2) {
db.execSQL(upgradeDatabaseToVersion2Sql);
}
if (oldVersion < 3) {
db.execSQL(upgradeDatabaseToVersion3Sql);
}
if (oldVersion < 4) {
db.execSQL(upgradeDatabaseToVersion4Sql);
}
}
关于 onUpgrade() 方法,官方说法是:
/**
在数据库版本升高时就会被触发,即在数据库需要升级时调用。使用此方法来做删除表、添加表或执行升级到新数据库结构版本所需的任何其他操作,从而实现升级。
关于 ALTER TABLE 的操作可以点击“http://sqlite.org/lang_altertable.html”链接来查看详细内容,如果添加新列,可以使用ALTER TABLE将它们插入活动表。如果重命名或删除列,可以使用ALTER 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);
有升级就有降级,当然在实际应用中使用的很少,比如:我们将 DATABASE_VERSION 从 3 改为 2 , 自动触发 onDowngrade() 方法,如下所示:
//测试一下回滚DB, 数据库降级,数据库版本从3降到2
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion > 2) { //DATABASE_VERSION == 3
db.execSQL("DROP TABLE IF EXISTS company");
}
// super.onDowngrade(db, oldVersion, newVersion);
}
因为数据库的操作是耗时操作,所以你不应该在主线程中进行数据库的操作,将 getWritableDatabase() 和 getReadableDatabase() 放到后台线程中处理,比如利用 AsyncTask 或 IntentService 来进行数据库的操作。如下利用 AsyncTask 来进行删除的操作:
private static class DeleteBusinessCardAsyncTask extends AsyncTask {
private WeakReference contextWeakReference;
DeleteBusinessCardAsyncTask(Context context) {
contextWeakReference = new WeakReference<>(context);
}
@Override
protected Void doInBackground(Integer... integers) {
Context context = contextWeakReference.get();
if (context != null) {
new DataBaseHelper(context).deleteBusinessCard(integers[0]);
}
return null;
}
}
源码见 -> Android_SQLite_Learning