Room

1.引入依赖

implementation "android.arch.persistence.room:runtime:1.0.0"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0"

2.Room三大组件

  • Database: 用这个组件创建一个数据库。注解定义了一系列entities,并且类中提供一系列Dao的抽象方法,也是下层主要连接的访问点。注解的类应该是一个继承 RoomDatabase的抽象类。在运行时,你能通过调用Room.databaseBuilder()或者 Room.inMemoryDatabaseBuilder()获得一个实例
  • Entity: 用这个组件创建表,Database类中的entities数组通过引用这些entity类创建数据库表。每个entity中的字段都会被持久化到数据库中,除非用@Ignore注解
  • DAO: 这个组件代表了一个用来操作表增删改查的dao。Dao 是Room中的主要组件,负责定义访问数据库的方法。被注解@Database的类必须包含一个没有参数的且返回注解为@Dao的类的抽象方法。在编译时,Room创建一个这个类的实现。

    简要来说,
    @Database用来注释表示数据库的类(需要定义成抽象类继承自RoomDatabase),在注释后面的括号内声明entities将表写进去,并写一下version,类中需要有一个抽象的Dao的构造方法,方便操作Dao中的方法
    @Entity用来注释一个类,这个类表示一个表,在里面声明表中的字段,@PrimaryKey注释主键(可以在其后面的括号内注释autoIncrement = true代表自增),@ColumInfo注释其他的字段,在其后面的括号内注释name代表其在数据库中的名字,然后设置set/get方法
    @Dao注释一个接口,这个接口包含操作数据库的方法,@Query,@Insert,@Delete,@Update分别对应增删改查,在@Query后面的括号中写具体的sql语句

在MainActivity中,调用Room.databaseBuilder().build创建数据库,记住数据库的操作需要在子线程中执行,如果想在主线程中执行需要在创建数据库时声明.allowMainThreadQueries()

MyEntity.class

@Entity
public class MyEnity {
    @PrimaryKey(autoGenerate = true)
    private int id;
    @ColumnInfo(name = "user_name")
    private String name;
    @ColumnInfo(name = "user_phone_number")
    private long phoneNumber;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public long getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(long phoneNumber) {
        this.phoneNumber = phoneNumber;
    }
}

MyDao.class

@Dao
public interface MyDao {

    @Query("SELECT * from myenity")
    List<MyEnity> getAll();

    @Query("select * from myenity where id = :uid")
    MyEnity getUserById(int uid);

    @Insert
    void insertAll(MyEnity... myEnity);

    @Delete
    void delete(MyEnity myEnity);
}

MyDatabase.class

@Database(entities = {MyEnity.class},version = 1)
public abstract class MyDatabase extends RoomDatabase {
    public abstract MyDao myDao();
}

MainActivity.class

public class MainActivity extends AppCompatActivity {

    private final static String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                MyDatabase myDatabase = Room.databaseBuilder(MainActivity.this,MyDatabase.class,"database-name").build();
                MyEnity myEnity = new MyEnity();
                myEnity.setName("shaarawy");
                myEnity.setPhoneNumber(123456);
                myDatabase.myDao().insertAll(myEnity);
                MyEnity myEnity1 = myDatabase.myDao().getUserById(1);
                Log.d(TAG, "onCreate: " + myEnity1.getName());
            }
        }).start();

    }
}

运行结果
这里写图片描述

3.一些知识点

  • PrimaryKey

对于组合的主键

@Entity(primaryKeys = {"firstName", "lastName"})
class User {
    public String firstName;
    public String lastName;
}

Room默认把类名作为数据库的表名。如果你想用其它的名称,使用@Entity注解的tableName属性

Room默认把field名称作为数据库表的column名。如果你想让column有不一样的名称,为field添加@ColumnInfo属性

  • Indices 和 uniqueness

为了提高查询的效率,你可能想为特定的字段建立索引。要为一个entity添加索引,在@Entity注解中添加indices属性,列出你想放在索引或者组合索引中的字段

@Entity(indices = {@Index("name"), @Index("last_name", "address")})
class User {
    @PrimaryKey
    public int id;

    public String firstName;
    public String address;

    @ColumnInfo(name = "last_name")
    public String lastName;

    @Ignore
    Bitmap picture;
}

有时候,某个字段或者几个字段必须是唯一的。你可以通过把@Index注解的unique属性设置为true来实现唯一性。

@Entity(indices = {@Index(value = {"first_name", "last_name"},
        unique = true)})
class User {
    @PrimaryKey
    public int id;

    @ColumnInfo(name = "first_name")
    public String firstName;

    @ColumnInfo(name = "last_name")
    public String lastName;

    @Ignore
    Bitmap picture;
}
  • 外键

假设有另外一个表Book,可以使用@ForeignKey来定义外键。

@Entity(foreignKeys = @ForeignKey(entity = User.class,
                                  parentColumns = "id",
                                  childColumns = "user_id"))
class Book {
    @PrimaryKey
    public int bookId;

    public String title;

    @ColumnInfo(name = "user_id")
    public int userId;
}
  • 嵌套对象

有时你可能想把一个entity或者一个POJO作为一个整体看待,即使这个对象包含几个field。这种情况下,你可以使用@Embedded注解,表示你想把一个对象分解为表的子字段。然后你就可以像其它独立字段那样查询这些嵌入的字段。

class Address {
    public String street;
    public String state;
    public String city;

    @ColumnInfo(name = "post_code")
    public int postCode;
}

@Entity
class User {
    @PrimaryKey
    public int id;

    public String firstName;

    @Embedded
    public Address address;
}

4.Dao的方法

  • insert

当你创建了一个DAO方法并且添加了@Insert注解,Room生成一个实现,将所有的参数在一次事务中插入数据库。

@Dao
public interface MyDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public void insertUsers(User... users);

    @Insert
    public void insertBothUsers(User user1, User user2);

    @Insert
    public void insertUsersAndFriends(User user, List<User> friends);
}

如果@Insert方法只接收一个参数,它可以返回一个long,代表新插入元素的rowId,如果参数是一个数组或者集合,那么应该返回long[]或者List。

  • update

Update是一个更新一系列entity的简便方法。它根据每个entity的主键作为更新的依据。

@Dao
public interface MyDao {
    @Update
    public void updateUsers(User... users);
}
  • delete

用于删除一系列entity。它使用主键找到要删除的entity。

@Dao
public interface MyDao {
    @Delete
    public void deleteUsers(User... users);
}
  • query

@Query是DAO类中主要被使用的注解。它允许你在数据库中执行读写操作。每个@Query方法都是在编译时检查,因此如果查询存在问题,将出现编译错误,而不是在运行时引起崩溃。

Room还会检查查询的返回值,如果返回的对象的字段名和查询结果的相应字段名不匹配,Room将以下面两种方式提醒你:

  • 如果某些字段名不匹配给出警告。
  • 如果没有匹配的字段名给出错误提示。
@Dao 
public interface MyDao { 
    @Query(“SELECT * FROM user”) 
    public User[] loadAllUsers(); 
}
@Dao
public interface MyDao {
    @Query("SELECT * FROM user WHERE age > :minAge")
    public User[] loadAllUsersOlderThan(int minAge);
}
@Dao
public interface MyDao {
    @Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
    public User[] loadAllUsersBetweenAges(int minAge, int maxAge);

    @Query("SELECT * FROM user WHERE first_name LIKE :search "
           + "OR last_name LIKE :search")
    public List<User> findUserWithName(String search);
}
  • 返回字段的子集

大多数时候,我们只需要一个entity的部分字段。比如,你的界面也许只需显示user的first name 和 last name,而不是用户的每个详细信息。只获取UI需要的字段可以节省可观的资源,查询也更快。

只要结果的字段可以和返回的对象匹配,Room允许返回任何的Java对象。比如,你可以创建如下的POJO获取user的first name 和 last name:

public class NameTuple {
    @ColumnInfo(name="first_name")
    public String firstName;

    @ColumnInfo(name="last_name")
    public String lastName;
}
@Dao
public interface MyDao {
    @Query("SELECT first_name, last_name FROM user")
    public List<NameTuple> loadFullName();
}
  • 传入参数集合

一些查询可能需要你传入个数是一个变量的参数,只有在运行时才知道具体的参数个数。比如,你可能想获取一个区间的用户信息。当一个参数代表一个集合的时候Room是知道的,它在运行时自动根据提供的参数个数扩展。

@Dao
public interface MyDao {
    @Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
    public List<NameTuple> loadUsersFromRegions(List<String> regions);
}
  • 可观察的查询

当执行查询的时候,你通常希望app的UI能自动在数据更新的时候更新。为此,在query方法中使用LiveData类型的返回值。当数据库变化的时候,Room会生成所有的必要代码来更新LiveData。

@Dao
public interface MyDao {
    @Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
    public LiveData<List<User>> loadUsersFromRegionsSync(List<String> regions);
}
  • RxJava

Room还可以让你定义的查询返回RxJava2的Publisher和Flowable对象。要使用这个功能,在Gradle dependencies中添加android.arch.persistence.room:rxjava2。然后你就可以返回RxJava2中定义的对象类型了,如下面的代码所示:

@Dao
public interface MyDao {
    @Query("SELECT * from user where id = :id LIMIT 1")
    public Flowable<User> loadUserById(int id);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值