谷歌在开发新的技术的同时也在架构上不断给大家在架构上推出新的思路旨在减少代码的耦合度提高项目的扩展性,从最初引入java的MVC理念到MVP,再到15年的MVVM,去年谷歌大会又推出了新的架构理念AAC,在这里我们首先着重介绍AAC的相关组件当大家对这些组件了解后再对整体AAC架构进行分析。
Room是谷歌新推出的一个数据库的架构,使用起来很方便下面,下面我将从3个方面对数据库的使用进行分析。
1.数据库实体类(Entity)
@Entity(tableName = "user", indices = {@Index(value = "id", unique = true), @Index(value = {"userName", "passWord"})})
public class User {
@PrimaryKey(autoGenerate = true)
private int id;
@ColumnInfo(name = "userName")
private String userName;
@ColumnInfo(name = "passWord")
private String passWord;
@ColumnInfo(name = "age")
private int age;
@ColumnInfo(name = "height")
private int height;
@Ignore
private boolean isVip;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public boolean isVip() {
return isVip;
}
public void setVip(boolean vip) {
isVip = vip;
}
}
这里咱们对这几个注解进行一一分析。
Entity
public @interface Entity {
//表名称
String tableName() default "";
//关联索引集合
Index[] indices() default {};
//父类的索引是否会自动被当前类继承(没遇到过这种情况大家遇到了可以分析分析)
boolean inheritSuperIndices() default false;
//关联主键集合
String[] primaryKeys() default {};
//外键集合
ForeignKey[] foreignKeys() default {};
}
基本上跟表属性相关的设置都有体现tableName定义数据库表的名称,indices关联索引集合用于提高检索效率(后面会对Index这个索引注解进行分析),primaryKeys如果我们的数据库表需要使用多个主键进行定义数据唯一性可以在这里添加关联的主键,foreignKeys定义相关外键(个人对于外键的使用并不是很推荐觉得不定义外键数据灵活性更大喜欢的可以自己研究下)。
Index
public @interface Index {
//索引列集合
String[] value();
//索引名称
String name() default "";
//是否具有唯一性
boolean unique() default false;
}
索引value定义了索引包含的列,name表示索引的名称,unique这个很关键如果设置为了true则表示这些关联的索引具有了唯一性起到了关联主键的作用如果相同关联索引数据插入数据库会报异常。
PrimaryKey
public @interface PrimaryKey {
//主键是否自增
boolean autoGenerate() default false;
}
PrimaryKey 用来标注主键如果是int类型的主键设置autoGenerate则代表是个自增的主键。
ColumnInfo
public @interface ColumnInfo {
//列名称
String name() default INHERIT_FIELD_NAME;
@SuppressWarnings("unused") @SQLiteTypeAffinity int typeAffinity() default UNDEFINED;
//是否为主键
boolean index() default false;
@Collate int collate() default UNSPECIFIED;
String INHERIT_FIELD_NAME = "[field-name]";
int UNDEFINED = 1;
int TEXT = 2;
int INTEGER = 3;
int REAL = 4;
int BLOB = 5;
@IntDef({UNDEFINED, TEXT, INTEGER, REAL, BLOB})
@interface SQLiteTypeAffinity {
}
int UNSPECIFIED = 1;
int BINARY = 2;
int NOCASE = 3;
int RTRIM = 4;
@RequiresApi(21)
int LOCALIZED = 5;
@RequiresApi(21)
int UNICODE = 6;
@IntDef({UNSPECIFIED, BINARY, NOCASE, RTRIM, LOCALIZED, UNICODE})
@interface Collate {
}
}
感觉ColumnInfo也就名称用一下指定下列名
2.数据操作对象(Dao)
到使我们定义要处理数据库相关数据的操作集合例子如下
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
public List<User> getUsers();
@Query("SELECT * FROM user WHERE id=:id")
public User getUserById(int id);
@Insert
public void insert(List<User> users);
@Delete
public void deleteUser(User user);
@Update
public void updateUser(User user);
}
插入删除修改就不再介绍了简单的把对象放进去即可
我们重点来看查询Query指定相关的sql这样就能得到我们需要的数据集合,如果需要参数只需要使用 : 指定参数是哪一个参数即可,是不是很简单,别忘了添加@Dao这个注解。
2.数据库对象(Database)
@Database(entities = {User.class}, version = 3,exportSchema =false)
public abstract class UserDB extends RoomDatabase {
public abstract UserDao getUserDao();
}
Database这个对象我们需要指定三个参数entities 代表数据库需要操作的实体类集合,第二个参数代表数据库的版本第三个参数代表在编译时,将数据库的模式信息导出到JSON文件中,这样可有利于我们更好的调试和排错,这里我们设置为了false即不导出到json文件中,一般数据库本身问题看LOG很容易发现。
room操作的类型为基本类型如果我们需要操作Date 类型则需要写一个下面的类
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();
}
}
最后将这个类添加到db类中
@Database(entities = {User.class}, version = 3,exportSchema =false)
@TypeConverters({Converter.class})
public abstract class UserDB extends RoomDatabase {
public abstract UserDao getUserDao();
}
最后就是调用的过程了代码也是很简单
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
UserDB db = Room.databaseBuilder(MainActivity.this, UserDB.class, "userDB.db")
.addCallback(new RoomDatabase.Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
}
@Override
public void onOpen(@NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
}
}).addMigrations(new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
// database.execSQL();
int aas=0;
}
},new Migration(2, 3) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
// database.execSQL();
int aas=0;
}
})
.allowMainThreadQueries()
.build();
UserDao dao = db.getUserDao();
User user = new User();
user.setAge(12);
user.setHeight(112);
user.setUserName("lanfang");
user.setPassWord("123");
user.setVip(false);
//增
List<User> users = new ArrayList<>();
users.add(user);
dao.insert(users);
/* //删
user.setId(2);
dao.deleteUser(user);*/
// 改
/* user.setId(1);
user.setAge(122);
user.setHeight(1121);
user.setUserName("lanfang1");
user.setPassWord("123333");
user.setVip(false);
dao.updateUser(user);*/
//查 全部
List<User> ss = dao.getUsers();
int a = ss.size();
//查 单条
User user1 = dao.getUserById(1);
int height = user1.getHeight();
}
}
首先利用 Room.databaseBuilder创建DB对象指定回调,数据库升级的处理
然后创建dao实例
最后通过dao进行数据库操作。
是不是很简单。
最后我们在分析下这个orm框架
优点
1.采用编译时注解大大提升了数据处理效果(大家可以通过类查询看到它为自己生成了UserDao_Impl这个类)因此不用考虑在运行时反射给性能带来的负担。
2.使用很简单三步走战略 创建entity 创建db 创建dao
3.谷歌自己的东西所以用起来放心
缺点
1.需要写sql(个人认为写sql很简单的逻辑自己还好控制)
2.通过@Database(entities = {User.class}, version = 3,exportSchema =false)这个注解我们看到这东西指定了需要操纵的数据库也就是不能自动升级数据库,如果要升级数据库只能改代码发新的apk。
有时间对这个数据库再进行封装处理,希望能帮助到大家。