Android中的五種存儲方式:SharePreferences,File I/O,SQLite,ContentPreferences,網絡。
- 網絡存儲:一定固定的路徑可以獲取到相關信息;
- File I/O(文件存儲):便於攜帶和分享;
- SQLite(數據庫):通過事前管理的機制,數據處理高效;
- ContentPreferences(內容提供者):跨app傳輸數據,速度取決於存儲數據的獲取的類型和大小;
- SharePreferences(配置共享):配置存儲,並非專門用於數據持久化存儲。
一.五種存儲方式的基礎原理:
- 網絡存儲使用http協議或者socket通信作爲傳輸方式。http底層也是通過短時間的socket通信來實現的傳輸。HttpClient很早已經被Android API23廢棄,隨後替換成HttpURLConnection,現在提倡更高效的OkHttp。我們通過一些流行的如retrofit/volley等網絡框架來發送/接收數據,其數據格式一般爲XML,JSON格式。
- File I/O操作數據通過字節流操作來完成,直接對二進制數據進行處理。
- SQLite是輕量級數據庫,通過SQLiteOpenHelper來封裝入口,然後調用SQLiteDataBase進行操作,SQLiteConnection中包含許多Native方法,通過JNI與SQLite3進行交互。
- ContentProvider在不同的應用程序中共享數據時,其數據的暴露方式是採取類似數據庫中表的方法。而ContentResolver恰好採用類似數據看的方法來從ContentProvider中存取數據,通過Uri來查詢ContentProvider中提供的數據。當調用ContentResolver的insert/delete/update/query方法中任何一個時,如ContentProvider所在的進程沒有啓動,則會觸發ContentProvider的創建,並伴隨着ContentProvider所在的進程的啓動,通過Binder機制獲取到Native層實際執行方法的對象。
- SharePreferences是一種輕量級的數據存儲機制,它將一些簡單數據類型的數據,包括數制類型/String類型數據以鍵值對的形式存儲在應用程序的私有SharePreferences目錄中。通過將鍵值對以XML格式保存到私有的XML文件中,其原理是對XML文件的拼寫修改。
二.組件化存儲:
Android原生的存儲體系是全局的,在組件化的開發中,五種原生的存儲方式完全通用的。greenDAO是一種對象關係映射(ORM)的框架,能夠提供一個接口,通過操作對象的方式去操作關係型數據庫,它能夠讓你在操作庫時更簡單方便。其原理是將一個實體對象轉化成一項數據,然後保存到SQLiteDatabase中,底層還是通過操作SQLiteDatabase來完成數據庫操作的。因爲底層使用的是SQLiteDatabase,所以無法保存如圖片這樣大的對象。
greenDAO是目前衆多ORM數據庫中最穩定/速度最快/編寫體驗最好的框架,並且支持RxJava。
- 註解:@Entity聲明實體對象,@Id聲明索引,@Property聲明的是每個變量帶有的列名,默認@Property(nameInDb="name")。
@Entity
public class SettingsInfo {
@Id
private long id;
private int width;
private int height;
private int density;
private String recordPath;
}
- 第一次編譯會生成DaoMaster,DaoSession和數據類名Dao文件。
- 通過封裝一個簡單的DBManger單例來操作Dao接口:
public class DBManger {
private volatile static DBManger instance;
private final static String dbName = "setting_db";
private DaoMaster.DevOpenHelper openHelper;
private SQLiteDatabase db;
private DaoMaster daoMaster;
private DaoSession daoSession;
private Context context;
public static DBManger getInstance() {
if (instance == null) {
synchronized (DBManger.class) {
if (instance == null) {
instance = new DBManger();
}
}
}
return instance;
}
public DBManger init(Context context) {
setDataBase(context);
return this;
}
private void setDataBase(Context context) {
openHelper = new DaoMaster.DevOpenHelper(context,dbName,null);
db = openHelper.getWritableDatabase();
daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
}
public DaoSession getDaoSession() {
return daoSession;
}
public SQLiteDatabase getDb() {
return db;
}
}
- 獲取SettingInfoDao對象:
SettingsInfoDao mSIDao = DBManger.getInstance().init(context).getDaoSession().getSettingsInfoDao();
- 讀取某項數據:
SettingsInfo settingsInfo = mSIDao.queryBuilder().where(SettingsInfoDao.Properties.Id.eq(0)).unique();
- 通過Dao對象寫入基礎數據:
mSIDao.insert(new SettingsInfo(0,1,2,3,"s"));
三.greenDao的優缺點及與Realm對比:
greenDao自動生成了DaoMaster,DaoSession,xxxDao是其優勢的地方,但也有其劣勢的地方:
- 無法侵入性地在這些文件中進行修改,因爲每次編譯都會重新編譯生成(替換)這些文件,無法在其中做任何操作;
- greenDao每次編譯都會替換編譯時註解生成的文件。
Realm在性能是插入和查詢速度要優於greenDao,刪除速度greenDao會較快;
需要考量的是greenDao的體積遠少於Realm,因爲greenDao使用Android底層的SQLite3,而Realm使用本身的數據庫查詢引擎,需要引入額外的so庫。Realm支持JSON和流式API也是優勢,另外也支持RxJava。
四.組件化數據庫:
原生的數據庫的運用範圍是整個app。但是當組件化使用關係型數據庫的時候,就需要考量解耦的問題。
問題的關鍵在與ORM原理——將實體對象轉化爲數據映射。原生數據庫是運用是直接對SQLiteDatabase進行數據庫操作,所以需要自身封裝對象。實體類放在本身的module中是無法傳遞的,需要放在一個統一的module中來管理這些類的產生和引用,其greenDao需要在Base module中引入,編寫時註解生成對象也應該放在Base module中,這樣全部的功能模塊才能引用到這個數據。
另一種是將數據庫層獨立爲一個模塊爲隨後的管理層,數據層將抽離/封裝和調用都可以統一XXXData的module中完成,這種組件是從Base基礎層分離出來的組件模塊,屬於更低的框架層。