Android Architecture Components(AAC)1 資料庫架構Room
谷歌在開發新的技術的同時也在架構上不斷給大家在架構上推出新的思路旨在減少程式碼的耦合度提高專案的擴充套件性,從最初引入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。 有時間對這個資料庫再進行封裝處理,希望能幫助到大家。