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