一、前言
1.菜鳥作者爲什麼要寫這篇呢?——隨GitHub上Android數據庫框架日新月異,我們應該如何選擇一個適合我們的數據庫。
當然一個好的數據庫框架不僅可以提高我們的開發效率外,還可以提高項目的性能。
2.爲什麼GitHub上有那麼多的開源框架?——不言而喻,應該是原生的開發效率與性能上沒有開源來的優秀(哈哈 個人觀點)
3.這篇主要寫什麼?——主要回顧數據庫的用法。對比一些開源數據庫的使用方法(最基礎的使用方式)。因性能弄起來比較麻煩,而且相關博客也很多大家自己百度即可。
二、效果預覽
隨便給自己寫的一個簡單Demo,看完UI有沒有一種想捏死作者的衝動...
這裏只涉及簡單的存儲操作,複雜的多對多關係這裏沒有。不瞞大家,想深入理解數據庫的同學可以止步了,這裏算基礎回顧
三、數據庫與框架的基礎使用
什麼是數據庫?什麼是SQLite?...就解釋到這裏。開始上菜了
先說明一下數據庫使用基礎步驟我把他們分爲:1.創建數據庫 2.創建表 3.數據庫操作(增刪改查) 4.更新數據庫
(1)第一道:原生數據庫
1.首先我們需要創建一個屬於自己的數據庫管理類來繼承SQLiteOpenHelper數據庫幫助類實現數據庫的創建與更新。
public class MySQLiteHelper extends SQLiteOpenHelper {
private static final String TAG = "MySQLiteHelper";
//數據庫建表語句
public static final String sql = "create table SqliteDemo (id integer primary key autoincrement, name text(4),address text(5))";
public static final String sql1 = "create table test1 (id integer primary key autoincrement, name text(4),address text(5))";
public MySQLiteHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);//創建數據庫調用方法
}
/**
* 第一次創建數據庫時調用 在這方法裏面可以進行建表
*/
@Override
public void onCreate(SQLiteDatabase db) {
Log.i(TAG, "onCreate: " );
db.execSQL(sql);
}
/**
* 版本更新的時候調用
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i(TAG, "onUpgrade: " );
switch (oldVersion){
case 1:
db.execSQL(sql1);
break;
}
}
}
創建一個數據庫:名稱Blcs 版本號 1
MySQLiteHelper blcs = new MySQLiteHelper(context, "Blcs", null, 1);
2.基本操作
//(1)打開數據庫並進行寫入操作
SQLiteDatabase db= blcs.getWritableDatabase();
注:Android提供了兩種操作方式:1.執行數據庫語句 2.調用封裝好的Api方法
增:插入一條語句
//方式一:
String insert = new StringBuilder()
.append("insert into SqliteDemo (name,address) values ('")
.append(name).append("','").append(address).append("')")
.toString();
//或是
//String insert = "insert into SqlteDemo (name,address) values ('"+name+"','"+address+"')";
db.execSQL(insert);
//方式二:
ContentValues contentValues = new ContentValues();
contentValues.put("name", name);
contentValues.put("address", address);
db.insert("SqliteDemo", null, contentValues);
刪:刪除一條語句
//方式一
String delete = new StringBuilder().append("delete from SqliteDemo where name = '").append(Name).append("' or address = '").append(Address).append("'").toString();
db.execSQL(delete);
//方式二
db.delete("SqliteDemo", "name = ? or address = ?", new String[]{Name, Address});
改:修改一條語句
//根據指定ID修改name 與 address
//方式一
String update = new StringBuilder().append("update SqliteDemo set name = '").append(Name)
.append("' , address = '").append(Address)
.append("' where id = ").append(Id)
.toString();
db.execSQL(update);
//方式二
ContentValues contentValues = new ContentValues();
contentValues.put("name", Name);
contentValues.put("address", Address);
db.update("SqliteDemo", contentValues, "id = ?", new String[]{String.valueOf(Id)});
查:查詢語句
//方式一
//查詢整張表
String query = "select * from SqliteDemo";
//獲取表中存在這個地址的數據
String query = new StringBuilder().append("select * from SqliteDemo where address = '")
.append(Address).append("'").toString();
//獲取表中存在這個地址和姓名的數據
String query = new StringBuilder().append("select * from SqliteDemo where name = '")
.append(Name).append("' and address = '").append(Address).append("'").toString();
//執行數據庫語句
Cursor cursor = db.rawQuery(query, null);
//方式二
//查詢整張表
String selection = null;
String str = null;
//獲取表中存在這個地址的數據
String selection = "address = ?";
String str = new String[]{Address};
//獲取表中存在這個地址和姓名的數據
String selection = "name = ? and address = ?";
String str = new String[]{Name, Address};
//執行相應的Api
Cursor cursor = db.query("SqliteDemo", null, selection, str, null, null, null);
還沒結束 ,當我們拿到Cursor對象後還要進行最後的數據獲取
ArrayList<SqliteDemo> dats = new ArrayList<>();
while (cursor.moveToNext()) {
SqliteDemo sqliteDemo = new SqliteDemo();
long id = cursor.getLong(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String address = cursor.getString(cursor.getColumnIndex("address"));
sqliteDemo.setId(id);
sqliteDemo.setName(name);
sqliteDemo.setAddress(address);
dats.add(sqliteDemo);
}
return dats;
3.數據庫更新
當我們數據庫有變化,並且要發佈新版本的時候別忘了升級一下數據庫版本號。並且還需要在MySQLiteHelper 的 onUpgrade方法中進行處理。
(2)第二道:LitePal框架
簡單描述:這是郭神早期對原生數據庫封裝的一個數據庫框架
優點嘛:......用了就知道了哈
GitHub:https://github.com/LitePalFramework/LitePal
guolin:https://blog.csdn.net/sinyu890807/column/info/android-database-pro
1.基本配置
1.添加依賴
dependencies {
implementation 'org.litepal.android:java:3.0.0'
}
or
dependencies {
implementation 'org.litepal.android:kotlin:3.0.0'
}
2,創建數據庫:在assets 添加litepal.xml //還有另外一種創建數據庫的方式 具體可以到GitHub或博客上了解
<?xml version="1.0" encoding="utf-8"?>
<litepal>
//數據庫暱稱
<dbname value="Blcs1" />
//版本號
<version value="1" />
//數據庫表
<list>
<mapping class="blcs.lwb.utils.bean.SqliteDemo" />
</list>
</litepal>
3.初始化 AndroidManifest.xml
<manifest>
<application
android:name="com.example.MyOwnApplication"
...
>
...
</application>
</manifest>
public class MyOwnApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
LitePal.initialize(this);
}
...
}
4.數據庫的操作
這裏對象需要繼承LitePalSupport,調用裏面的api執行相應的數據庫處理,可以給屬性相應的註解,相對簡單,這裏就不貼了。一切從簡
public class SqliteDemo extends LitePalSupport {
private Long id;
private String name;
private String address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
增
//創建要保存的對象,調用save方法直接保存 因爲繼承了LitePalSupport 裏面提供了許多保存的APi ,可以根據需求選擇合適的方法
SqliteDemo sqliteDemo = new SqliteDemo();
sqliteDemo.setName(name);
sqliteDemo.setAddress(address);
sqliteDemo.save();
//例:異步保存:開個線程進行保存,處理完監聽回調是否保存成功
sqliteDemo.saveAsync().listen(new SaveCallback() {
@Override
public void onFinish(boolean success) {
List<SqliteDemo> all = LitePal.findAll(SqliteDemo.class);
mAdapter.setNewData(all);
}
});
刪
//LitePal.delete();
//LitePal.deleteAll();
//LitePal.deleteAsync()
LitePal.deleteAllAsync(SqliteDemo.class,"name = ? or address = ?",Name,Address).listen(new UpdateOrDeleteCallback() {
@Override
public void onFinish(int rowsAffected) {
List<SqliteDemo> all = LitePal.findAll(SqliteDemo.class);
mAdapter.setNewData(all);
}
});
改
//LitePal.update();
//LitePal.updateAll();
//LitePal.updateAsync();
//LitePal.updateAllAsync();
ContentValues contentValues = new ContentValues();
contentValues.put("name", Name);
contentValues.put("address", Address);
LitePal.updateAsync(SqliteDemo.class,contentValues,Id).listen(new UpdateOrDeleteCallback() {
@Override
public void onFinish(int rowsAffected) {
List<SqliteDemo> all = LitePal.findAll(SqliteDemo.class);
mAdapter.setNewData(all);
}
});
查
//查詢全部
List<SqliteDemo> all = LitePal.findAll(SqliteDemo.class);
//獲取名字和地址對應的數據
String selection = "name = ? and address = ?";
List<SqliteDemo> all = LitePal.where(selection, Name, Address).find(SqliteDemo.class);
//查詢裏面隱藏着許多有用的Api,有興趣的同學可以繼續深究.這裏不解釋。否則導致篇幅太長
5.數據庫的更新
使用這個框架最大的優點是,我們已經不需要自己去寫數據庫的更新方法了。只需要提高一下版本號即可,剩下的框架已經都幫我們處理好了。
6.混淆
-keep class org.litepal.** {
*;
}
-keep class * extends org.litepal.crud.DataSupport {
*;
}
-keep class * extends org.litepal.crud.LitePalSupport {
*;
}
(3)第三道:GreenDao框架
greendao :https://github.com/greenrobot/greenDAO
介紹:http://greenrobot.org/greendao/documentation/
參考博客:https://www.jianshu.com/p/53083f782ea2
簡單描述:目前GitHub上最熱門的數據庫框架之一,相對其他數據庫框架star也是最多的一個。
1.基本配置
// In your root build.gradle file:
buildscript {
repositories {
jcenter()
mavenCentral() // add repository
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.1'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
}
}
// In your app projects build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
dependencies {
implementation 'org.greenrobot:greendao:3.2.2' // add library
}
混淆
-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties
-dontwarn org.greenrobot.greendao.database.**
-dontwarn rx.**
### greenDAO 2
-keepclassmembers class * extends de.greenrobot.dao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties
配置數據庫信息:
greendao {
schemaVersion 1 //數據庫版本號
// 設置DaoMaster、DaoSession、Dao 包名
daoPackage 'blcs.lwb.utils.greendao'
targetGenDir 'src/main/java'
}
2.創建持久化對象
主要:給持久化對象添加@Entity 註解 ,然後Build -- Make Project 重新編譯一下 會自動生成DaoMaster、DaoSession、GreenDaoDao
@Entity
public class GreenDao {
@Id
private Long id;
private String name;
private String address;
@Generated(hash = 534050545)
public GreenDao(Long id, String name, String address) {
this.id = id;
this.name = name;
this.address = address;
}
@Generated(hash = 766040118)
public GreenDao() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return this.address;
}
public void setAddress(String address) {
this.address = address;
}
}
3.創建數據庫
public class MyApplication extends BaseApplication {
@Override
public void onCreate() {
super.onCreate();
//GreenDao
initGreenDao();
}
private void initGreenDao() {
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "Blcs2.db");
SQLiteDatabase db = helper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
}
private static DaoSession daoSession;
public static DaoSession getDaoSession() {
return daoSession;
}
}
4.基本操作
//獲取GreenDao數據庫操作對象
DaoSession daoSession = MyApplication.getDaoSession();
//獲取指定的操作對象
GreenDaoDao greenDaoDao = daoSession.getGreenDaoDao();
增
GreenDao demo = new GreenDao();
demo.setName(name);
demo.setAddress(address);
daoSession.insert(demo);
//或
greenDaoDao.insert(demo);
刪
//查出需要刪除的對象 ,然後進行刪除
daoSession.delete(bean);
//或
greenDaoDao.delete(bean);
改
//根據ID查找某個對象進行更改
List<GreenDao> demos = daoSession.queryRaw(GreenDao.class, "where _id = ?", "" + Id);
GreenDao demo = demos.get(0);
demo.setName(Name);
demo.setAddress(Address);
daoSession.update(demo);
//或
greenDaoDao.update(demo);
查
//查詢全部
List<GreenDao> greenDaoBeans = daoSession.loadAll(GreenDao.class);
//根據條件查詢
List<GreenDao> greenDaoBeans = daoSession.queryRaw(GreenDao.class, "where NAME = ? and ADDRESS = ?", Name,Address);
大部分daoSession操作方法 ,greenDaoDao也會有
4.數據庫更新
GreenDao的OpenHelper下有個 onUpgrade(Database db, int oldVersion, int newVersion)方法,當設置的數據庫版本改變時,在數據庫初始化的時候就會回調到這個方法,我們可以通過繼承OpenHelper重寫onUpgrade方法來實現數據庫更新操作。
注:如果沒有重寫更新方法只升級版本號的話:會導致數據丟失。
四、總結
使用原生數據庫容易出現語句錯誤,使用繁瑣,提供的Api也比較少。相對於原生數據庫,我們可以採用郭神的LitePal框架,主要是基於原生數據庫封裝的。提供的Api比較豐富,而且使用也方便。
但是從性能方面上來看可能沒有GreenDdao框架高,具體可以查看GreenDdao文檔。裏面有進行詳細的描述。
當然還有許多不錯的數據框架:DBFlow、ActiveAndroid、ORMLite、Realm、Afinal ....
最後在推薦一個性能更好的數據庫框架objectbox
GitHub:https://github.com/objectbox/objectbox-java
爲什麼菜鳥作者不寫呢?——還在學習中..
注:AS中並不能直接打開.db文件 所以一般要查看數據庫文件需要藉助工具
不過那樣會很麻煩,需要先找到文件導出後再工具中查看。
所以這裏可以引用Android-Debug-Database,在不借助工具的情況下查看數據庫。
五、Demo地址
Github:https://github.com/DayorNight/BLCS
碼雲:https://gitee.com/blcs/BLCS
apk下載體驗地址:https://www.pgyer.com/BLCS
六、內容推薦
《Android Notification通知簡單封裝(適配8.0)》
如果你覺得寫的不錯或者對您有所幫助的話
不妨頂一個【微笑】,別忘了點贊、收藏、加關注哈
看在花了這麼多時間整理寫成文章分享給大家的份上,記得手下留情哈
您的每個舉動都是對我莫大的支持