Android AAC学习(二)

在第一节中主要介绍了Licycle、LiveData以及ViewModel的简单使用,这一节记录一下Room的学习。

什么是Room?

附上官方文档:https://developer.android.google.cn/training/data-storage/room/index.html

Room持久库提供了一个SQLite抽象层,使得我们访问数据更加的稳健,提升数据库性能。能够让用户在无网络连接的情况下继续使用APP。连接网络后对服务器的数据进行更新。

引用官方的一张框架图,更好的解释Room的作用以及意义:

在这里插入图片描述

Room数据持久层框架只要由三个组件构成:

  1. RoomDatabase
    包含数据库持有者,充当与应用程序持久化的、关系型的数据的底层连接的主要访问点
    获取实例时,必须使用@Database注解,指定entities以及version;继承至RoomDatabase且使用abstract修饰;内部必须包含一个无参且返回Dao层(使用@Dao注解)抽象方法;
    运行时通过调用Room.databaseBuilder()Room.inMemoryDatabaseBilder()获取数据库实例。
  2. Entity:表示数据库内的表,@Entity注解
  3. Dao:包含访问数据库的方法,被@Dao所注解

简单的使用:

导入库:https://developer.android.google.cn/jetpack/androidx/releases/room

	def room_version = "2.1.0-alpha06"

    implementation "androidx.room:room-runtime:$room_version"
    annotationProcessor "androidx.room:room-compiler:$room_version" // use kapt for Kotlin

    // optional - RxJava support for Room
    implementation "androidx.room:room-rxjava2:$room_version"
  1. Book–Entity层:
import android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.Ignore;
import android.arch.persistence.room.PrimaryKey;

/**
 * 创建时间: 2019/3/26 16:58
 * 描述:    TODO
 */
@SuppressWarnings("unused")
@Entity
public class Book {
    @PrimaryKey(autoGenerate = true)
    public long id;
    @ColumnInfo(name = "book_name")
    public String bookName;
    @ColumnInfo(name = "book_price")
    public double price;
    @Ignore
    public String ISBN;

    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", bookName='" + bookName + '\'' +
                ", price=" + price +
                ", ISBN='" + ISBN + '\'' +
                '}';
    }
}
  1. BookDao–Dao层:
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.Query;

import java.util.List;

@Dao
public interface BookDao {
    @Insert
    void insert(Book book);

    @Query("select * from book")
    List<Book> getBooks();

    @Delete
    void delete(long id);

    @Query("SELECT * FROM book WHERE id IN (:bookIds)")
    List<Book> loadAllByIds(long[] bookIds);
}
  1. Database:
import android.arch.persistence.room.Database;
import android.arch.persistence.room.RoomDatabase;

/**
 * 创建时间: 2019/3/26 16:54
 * 描述:    TODO
 */
@SuppressWarnings("unused")
@Database(entities = {Book.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract BookDao getBookDao();
}
  1. 获取数据库实例且使用:

单进程中,尽量使用单例来获取数据库实例,因为获取数据库实例耗时且浪费资源。
多进程中,在build的过程中添加enableMultiInstanceInvalidation(),每个进程都持有一个数据库实例的引用。

 mAppDatabase = Room.databaseBuilder(this, AppDatabase.class, "book.db")
                .allowMainThreadQueries()                // 允许在主线程中访问数据库
                .addMigrations(MIGRATION_1_2, MIGRATION_2_3)  // 数据库升级的逻辑
                .build();
                
 static final Migration MIGRATION_1_2 = new Migration(1, 2) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("ALTER TABLE Book ADD COLUMN count integer");
        }
    };

    static final Migration MIGRATION_2_3 = new Migration(2, 3) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("");
        }
    };


	// 使用
	 App.getInstance().getAppDatabase().getBookDao().insert(book);
     List<Book> books = App.getInstance().getAppDatabase().getBookDao().getBooks();

Entity的详细介绍

Room库会将使用了@Entity注解的实体类自动映射到Database中转换成表。

常用的注解有:

注解作用
@PrimaryKey定义主键
@ColumnInfo定义列
@Ignore过滤,不想持久化的字段
@Embedded嵌入实体
@Index索引相关
  • 使用@Entity定义实体
    注意:默认使用类名当作表名,可通过tableName指定表名,不区分大小写。
@Entity(tableName = "address")
public class Address {
    @PrimaryKey
    public long addId;
    public String add;
}
  • 使用@PrimaryKey定义主键
    每个实体类至少包含一个主键,即使只有1个字段,仍然需要用@PrimaryKey注解字段;想要自动分配ID给主键,在注解中加入
    autoGenerate = true即可;如果实体具有复合组件使用primaryKeys = {"firstName","lastName"}即可。
@Entity(tableName = "user",primaryKeys = {"firstName","lastName"})
public class User {
    @PrimaryKey(autoGenerate = true)
    public long userId;
    public String firstName;
    public String lastName;
}
  • 默认使用属性名作为表的列名,可使用@ColumnInfo(name="xx")自定义列名
@Entity
public class Book {
    @PrimaryKey(autoGenerate = true)
    public long id;
    @ColumnInfo(name = "book_name")
    public String bookName;
    @ColumnInfo(name = "book_price")
    public double price;
}
  • 忽略字段
    让某个字段不被加入到数据库中,使用@Ignore注解即可。
@Entity
public class Book {
    @PrimaryKey(autoGenerate = true)
    public long id;
    @ColumnInfo(name = "book_name")
    public String bookName;
    @ColumnInfo(name = "book_price")
    public double price;
    @Ignore
    public String ISBN;
}

实体类继承自某个实体类,要忽略父类的属性如何实现?使用ignoredColumns即可

@Entity(ignoredColumns = "ISBN")
public class PaperBook extends Book{
    @PrimaryKey
    public int paper;
    public boolean hasPaper;
}
  • 支持全文搜索(Full-text Search 简称FTS),即创建一张虚拟表用来查询
    需要在Room 2.1.0以上且在实体上添加@Fts3或者@Fts4注解即可。

仅当您的应用程序具有严格的磁盘空间要求或者您有时,才使用@ Fts3
需要与较旧的SQLite版本兼容。
FTS表支持的实体指定主键是可选的,但是如果包含一个,则必须使用此类型和列名称。

@Fts4
@Entity(ignoredColumns = "ISBN")
public class PaperBook extends Book{
    @PrimaryKey
    //FTS表支持的实体指定主键是可选的,但是如果包含一个,则必须使用此类型和列名称。
    @ColumnInfo(name = "rowid")
    public int paper;
    public boolean hasPaper;
}

注意:启用FTS的表始终使用INTEGER类型的主键和列名“rowid”。 如果由FTS表支持的实体定义主键,则必须使用该类型和列名称。

  • 索引
    可以索引数据库中的某些列以加快查询速度。 要向实体添加索引,请在@Entity批注中包含indices属性,列出要包含在索引或复合索引中的列的名称。
@Entity(indices = {@Index("name"), @Index(value = {"firstName", "address"})})
public class User {
    @PrimaryKey(autoGenerate = true)
    public long userId;
    public String firstName;
    public String lastName;
    public String address;
}

数据库中的某些字段或字段组必须是唯一的。可以通过将@Index注解的唯一属性设置为true来强制执行此唯一性属性。下面的代码示例防止表中包含两个行,它们包含firstName和address列的相同值集:

@Entity(indices = {@Index(value = {"firstName", "address"},unique = true)})
public class User {
    @PrimaryKey(autoGenerate = true)
    public long userId;
    public String firstName;
    public String lastName;
    public String address;
}
  • AutoValue-based objects
    在2.1.0及更高版本的房间中,您可以使用基于Java的不可变值类(使用@AutoValue进行注释)作为应用程序数据库中的实体。 如果实体的两个实例的列包含相同的值,则认为这两个实例是相等的。如何使用?
@AutoValue
@Entity
public abstract class User {
    // Supported annotations must include `@CopyAnnotations`.
    @CopyAnnotations
    @PrimaryKey
    public abstract long getId();

    public abstract String getFirstName();
    public abstract String getLastName();

    // Room uses this factory method to create User objects.
    public static User create(long id, String firstName, String lastName) {
        return new AutoValue_User(id, firstName, lastName);
    }
}
  • 实体间的关系
  • 由于SQLite是关系数据库,因此您可以指定对象之间的关系。 尽管大多数对象关系映射库允许实体对象相互引用,但Room明确禁止这样做。即使您不能使用直接关系,Room仍允许您在实体之间定义外键约束。
    @Entity中加入foreignKeys = @ForeignKey(entity = User.class,
    parentColumns = “userId”,childColumns = “user_id”)

entity 为关联的实体类;parentColumns 在关联对象中的列名;childColumns在此对象中的列名

@Entity(foreignKeys = @ForeignKey(entity = User.class,
                                    parentColumns = "userId",childColumns = "user_id"))
public class Book {
    @PrimaryKey(autoGenerate = true)
    public long id;
    @ColumnInfo(name = "book_name")
    public String bookName;
    @ColumnInfo(name = "book_price")
    public double price;
    @Ignore
    public String ISBN;
    @ColumnInfo(name = "user_id")
    public int uId;
}

注意:外键非常强大,因为它们允许您指定更新引用实体时发生的情况。 例如,如果通过在@ForeignKey批注中包含onDelete = CASCADE来删除相应的User实例,则可以告诉SQLite删除用户的所有书籍。

  • 创建嵌套对象
    有时,您希望将实体或普通旧Java对象(POJO)表达为数据库逻辑中的一个整体,即使该对象包含多个字段。您可以像查询其他单个列一样查询嵌入字段。这种情况下我们可以使用@Embedded注解来实现。
public class Address {
    public long addId;
    public String city;
    public String province;
}

@Entity(indices = {@Index(value = {"firstName"},unique = true)})
public class User {
    @PrimaryKey(autoGenerate = true)
    public long userId;
    public String firstName;
    public String lastName;
    @Embedded
    public Address address;
}

这样我们就可以在User表中正常的使用Address中的属性。

注意:嵌入字段还可以包含其他嵌入字段。
如果实体具有多个相同类型的嵌入字段,则可以通过设置prefix属性使每个列保持唯一。然后,Room将提供的值添加到嵌入对象中每个列名称的开头。

Dao层的使用

如果使用过MySql以及SSM/Spring Boot框架的同学可以略过,因为基本方法的类似。以下是官网的关于Dao层的使用介绍:
https://developer.android.google.cn/training/data-storage/room/accessing-data

Room的相关学习就到这了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值