天天看點

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 = ;
    int TEXT = ;
    int INTEGER = ;
    int REAL = ;
    int BLOB = ;
    @IntDef({UNDEFINED, TEXT, INTEGER, REAL, BLOB})
    @interface SQLiteTypeAffinity {
    }
    int UNSPECIFIED = ;
    int BINARY = ;
    int NOCASE = ;
    int RTRIM = ;
    @RequiresApi()
    int LOCALIZED = ;
    @RequiresApi()
    int UNICODE = ;
    @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 = ,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 = ,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(, ) {
                    @Override
                    public void migrate(@NonNull SupportSQLiteDatabase database) {
//                                database.execSQL();
                        int aas=;

                    }
                },new Migration(, ) {
                    @Override
                    public void migrate(@NonNull SupportSQLiteDatabase database) {
//                                database.execSQL();
                        int aas=;

                    }
                })
                .allowMainThreadQueries()
                .build();
        UserDao dao = db.getUserDao();
        User user = new User();
        user.setAge();
        user.setHeight();
        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();
        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。

有時間對這個資料庫再進行封裝處理,希望能幫助到大家。

下篇文章連結

GitHub傳送門

繼續閱讀