Android

Jetpack -room (一)基本使用

2019-06-23  本文已影响0人  Active_Loser

总结:个人见解,使用了一段时间,对于本地频繁操作数据库切数据结构复杂的应用来说,Room并不是很灵活,且需要有一定的SQL编写能力。

一、简介

Room是安卓中SQLite上的一个抽象层应用框架,可以更轻松、更好地保存数据。
我们目前较多使用的是Greendao(GreenDao3.0数据库的简单使用),我们对比执行SQL的效率以及对数据库的访问,可以考虑使用Room了。


Room的不同组件之间的这种关系如图:
取自developer.android.google.cn

注解:
Entity

@Entity:注解标识创建表,使用@Entity(tableName = "users")自定义表名
@ColumnInfo:注解标识数据库列,使用@ColumnInfo(name = "last_name")自定义列名
@Ignore:注解表示忽略此对象,数据库中不会创建此列;若使用继承,忽略父类的一个对象,使用@Entity(ignoredColumns = "picture")
@NonNull:非空
@PrimaryKey:注解表示为主键,使用@Entity(primaryKeys = {"firstName", "lastName"})表示复合主键,使用@PrimaryKey(autoGenerate = true)设置主键自且类型为INTEGER
indices: 对特定的field建立索引加速数据库访问,索引:@Entity(indices = @Index("name")) ,复合索引:@Entity(indices = @Index(value = {"last_name", "address"}))
@ForeignKey用于设置外键@Entity(foreignKeys = @ForeignKey(entity = User.class, parentColumns = "id",childColumns = "user_id"))

@Dao

@Dao:注解是一个数据访问对象
@Insert:注解插入

//onConflict = OnConflictStrategy.REPLACE 存在会替换
@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);

@Update注解更新

//返回类型为int的情况,表示更新对象的个数
@Update
public void updateUsers(User... users);

@Delete:注解为删除
注意:使用条件删除,不能通过@Delete去做,可以使用@Query('sql')去执行。

//返回类型为int的情况,表示删除对象的个数
@Delete
public void deleteUsers(User... users);

@Query:注解为查询

@Query("SELECT * FROM user")
 public User[] loadAllUsers();

@Query("SELECT * FROM user WHERE age > :minAge")
 public User[] loadAllUsersOlderThan(int minAge);

 @Query("SELECT first_name, last_name FROM user WHERE region IN (:regions)")
 public List<NameTuple> loadUsersFromRegions(List<String> regions);

//多表查询
 @Query("SELECT * FROM book " +
           "INNER JOIN loan ON loan.book_id = book.id " +
           "INNER JOIN user ON user.id = loan.user_id " +
           "WHERE user.name LIKE :userName")
   public List<Book> findBooksBorrowedByNameSync(String userName);

二、实战

这部分针对数据的增删改查,以及数据库升级、迁移、与Rxjava的结合使用做介绍

2.1、基本使用

添加依赖

implementation 'androidx.room:room-runtime:2.1.0'
annotationProcessor 'androidx.room:room-compiler:2.1.0'

(1)创建表实体

public class User {
    @PrimaryKey(autoGenerate = true)
    public int uid;

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

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

(2)创建Dao(SQ语法我们还是要学习的)

@Dao
public interface UserDao {
    @Query("SELECT * FROM user")
    List<User> getAll();

    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    List<User> loadAllByIds(int[] userIds);

    @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
            "last_name LIKE :last LIMIT 1")
    User findByName(String first, String last);

    @Insert
    void insertAll(User... users);

    @Delete
    void delete(User user);
}

(3)AppDatabase 使用单例,减少开销

@Database(entities = {User.class}, version = 1,exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
    //volatile防止重排序
    private static volatile AppDatabase mAppDatabase;

    public abstract UserDao userDao();

    public static AppDatabase getSingleton(Context context) {
        if (mAppDatabase == null) {
            synchronized (AppDatabase.class) {
                if (mAppDatabase == null) {
                    //主线程使用.allowMainThreadQueries().build();创建
                    mAppDatabase = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "user.db")
                            .allowMainThreadQueries()
                            .build();

                }
            }
        }
        return mAppDatabase;
    }
}

(4)使用

AppDatabase appDatabase = AppDatabase.getSingleton(this);
User user = new User(0,"张","三");
User user1 = new User(1,"李","四");
appDatabase.userDao().insertAll(user);
appDatabase.userDao().insertAll(user1);
List<User> userList = appDatabase.userDao().getAll();

2.2 类型转换器

定义类型转换器

public class Converters {
    @TypeConverter
    public static Date fromTimestamp(Long value) {
        return value == null ? null : new Date(value);
    }

    @TypeConverter
    public static Long dateToTimestamp(Date date) {
        return date == null ? null : date.getTime();
    }
}

使用类型转换器

(1) 放在Database,那么该数据库中的所有Daos和Entities都可以使用它。
(2) 放在Dao,Dao中的所有方法都可以使用它。
(3) 放在Entity,实体的所有字段都可以使用它。
(4) 放在Entity字段上,则只有该字段才能使用它。
(5) 放在Dao方法上,该方法的所有参数都可以使用它。

//放在Dao方法参数上,那么只有该字段才能使用它。
@TypeConverters({Converters.class})

2.3 与RxJava并肩作战

添加依赖

implementation 'androidx.room:room-rxjava2:2.1.0-beta01'

@Query方法:房间支持类型的返回值 Publisher, Flowable和 Observable`。

@Insert@Update@Delete方法:2.1.0室和更高版本支持返回类型的值 CompletableSingle<T>Maybe<T>

@Dao
public interface MyDao {
    @Query("SELECT * from user where id = :id LIMIT 1")
    public Flowable<User> loadUserById(int id);

    // Emits the number of users added to the database.
    @Insert
    public Maybe<Integer> insertLargeNumberOfUsers(List<User> users);

    // Makes sure that the operation finishes successfully.
    @Insert
    public Completable insertLargeNumberOfUsers(User... users);

    /* Emits the number of users removed from the database. Always emits at
       least one user. */
    @Delete
    public Single<Integer> deleteUsers(List<User> users);
}

2.4 数据库升级

要使迁移逻辑按预期运行,使用完整查询,而不是引用表示查询的常量,否则会造成数据丢失

static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("CREATE TABLE `Fruit` (`id` INTEGER, "
                + "`name` TEXT, PRIMARY KEY(`id`))");
    }
};

static final Migration MIGRATION_2_3 = new Migration(2, 3) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("ALTER TABLE Book "
                + " ADD COLUMN pub_year INTEGER");
    }
};

Room.databaseBuilder(getApplicationContext(), MyDb.class, "database-name")
        .addMigrations(MIGRATION_1_2, MIGRATION_2_3).build();
上一篇 下一篇

猜你喜欢

热点阅读