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基础层分离出来的组件模块,属于更低的框架层。