Android数据存储 | 青训营笔记

146 阅读5分钟

这是我参与「第四届青训营 」笔记创作活动的的第7天

一、前言

上一篇文章讲了android中的网络请求,这一次来学习一下android的数据存储吧。
文章的主要内容如下:

  • 存储方式对比
  • 数据库开源框架对比
  • Room数据库的使用

二、存储方式对比

android官方已经给我提供了几种持久化存储的方式,每一种都各有优缺点,我们来看下面这张图片对比一下吧。

image.png

SharedPreferences

SharedPreferences可以存储一些比较简单的数据,它通过键值对的方式进行存储,类似于Java中的Map。
通常我们可以用它来存储一些设置的数据,或者是用户的id这一类简单的数据。

文件存储

文件存储也是很常见的存储方式,一般用来存储图片、音频、视频这一类比较特殊的数据。

ContentProvider

ContentProvider可以用来共享其它App的数据。

SQLite

SQLite是一个小型的数据库,它的包体积只有几百k,比较适合用在手机设备上,它通常用来存储结构化的数据,比较说保存新闻列表、消息内容。

三、数据库开源框架对比

比较常见的数据库框架如以下几种。

image.png
每一种都有各自的优缺点,但Room数据库因为是Google官方的,对谷歌的JetPack系列的库有更好的兼容性,比如可以支持LiveData、协程。

四、Room数据库的使用

1. 引入包

在项目下的app目录中的build.gradle中的dependencies中添加依赖

dependencies {
    def room_version = "2.4.2"
    implementation "androidx.room:room-runtime:$room_version"
    annotationProcessor "androidx.room:room-compiler:$room_version"
}

2. 主要组件

  • 数据库类: 用于保存数据库并作为应用持久性数据底层连接的主要访问点。
  • 数据实体: 用于表示应用的数据库中的表。
  • 数据访问对象 (DAO): 提供您的应用可用于查询、更新、插入和删除数据库中的数据的方法。

3. 实现示例

假设现在有个需求,需要存储一个联系人的信息,假设一个联系人的信息有:联系人名、电话号码
当然我们一边都会给每个数据表增加一个编号主键。

(1) 编写实体类

实体类代码如下,其中@Entity注解用于标识这是一个数据库实体类,@PrimaryKey标明这是一个主键,autoGenerate为是否自增,@ColumnInfo注解可以设置数据表的列名(不加也是可以的)。

@Entity
public class Contact {

    @PrimaryKey(autoGenerate = true)
    private int id;

    @ColumnInfo(name = "name")
    private String name;

    @ColumnInfo(name = "phone_number")
    private String phoneNumber;
    
    // 省略setter、getter方法
    ...
    
    @Override
    public String toString() {
        return "Contact{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", phoneNumber='" + phoneNumber + ''' +
                '}';
    }

}

(2) 编写Dao(数据访问对象)接口

Dao接口代码如下,其中@Dao注解用于标识这是一个Dao类。
可以看到Room对数据库的操作主要的注解有:@Query、@Insert、@Update、@Delete,方便对应CURD,但是这里的Query不一样,它可以执行任何的sql语句。

@Dao
public interface ContactDao {
    @Query("SELECT * FROM contact")
    List<Contact> getAll();

    @Query("SELECT * FROM contact WHERE name LIKE :name LIMIT 1")
    Contact findByName(String name);
    
    @Insert
    void insertAll(Contact... contacts);

    @Update
    void update(Contact contact);
    
    @Delete
    void delete(Contact contacts);
}

(3) 编写数据库类

数据库类代码如下,@Database注解用于标识这是一个数据库类,entities可以设置此数据库包含的数据表(实体类),version用于数据库的版本号。
值得注意的是,数据库类是抽象类,Dao类是一个接口
因为Room框架在我们编译的时候会生成具体的实现类,按照规范,我们需要在数据库类定义对应的抽象方法来获取对应的Dao实例

@Database(entities = {Contact.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {

    public abstract ContactDao contactDao();

    private static volatile AppDatabase INSTANCE;

    public static AppDatabase get(Context context) {
        if (INSTANCE == null) {
            synchronized (AppDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                            AppDatabase.class, "database-name").build();
                }
            }
        }
        return INSTANCE;
    }
}

测试

需要注意的是,Room数据库默认不支持在主线程进行操作,这也是一个很好的规则,因为数据库操作本身就是一个耗时的操作,轻则可以引起界面卡顿,重则可能导致ANR,当然你可以在获取数据库类实例的时候设置允许在主线程操作,但Google并不推荐这样做。
测试代码如下,创建了一个Contact对象,并将它添加到数据库中,并查询数据库,然后输出Log。

new Thread(){
    @Override
    public void run() {
        super.run();
        // 获取ContactDao实例
        ContactDao contactDao = AppDatabase.get(getApplicationContext()).contactDao();
        Contact contact = new Contact();
        contact.setName("小林");
        contact.setPhoneNumber("10086");
        // 将contact对象添加到数据库
        contactDao.insertAll(contact);
        // 查询数据库
        List<Contact> all = contactDao.getAll();
        Log.d(TAG, "查询结果: " + all);
    }
}.start();

我们查看一下log,可以看到数据成功地插入并且成功地查询了。

image.png 关于Room数据库更多的操作可以查看:developer.android.google.cn/training/da…

五、总结

这里主要为大家介绍了android中常用的数据存储方式,并且比较了各种存储方式的优缺点以及常用的数据库框架,并且也介绍了Room数据库框架的简单使用。
除了Room框架之外,我也用过ObjectBox,ObjectBox相对于Room框架确实会快一些,不过它底层不是用的SQLite。
ObjectBox有几个好处,比如说支持动态更新表列,你可以在对某个表增加列之后几乎完全不需要做其它的操作,还有默认支持了CURD等常用的数据库操作,不用去编写常用的CURD方法,这个比较类似于mybatis-plus,我觉得还是挺不错的,当然Room数据库可以很好地支持Google的JetPack家族,所以各有优缺。

六、结语

如果喜欢或有所帮助的话,希望能点赞关注,鼓励一下作者。
如果文章有不正确或存疑的地方,欢迎评论指出。

参考

juejin.cn/post/712345… developer.android.google.cn/training/da…