天天看點

關于Android架構元件Room的簡單使用

前言:Room于2017年谷歌IO大會上被推出,當時伴随着推出的還有LiveData以及ViewModel。相比于如今Ormlite、GreenDao等架構的優勢,Room自帶支援LiveData與ViewModel。這篇文章隻是簡單的介紹下Room的使用,并不涉及LiveData與ViewModel的組合使用。後續文章再加上吧。

廢話不多說,進入正題。

首先,導入使用Room

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

使用Room的關鍵有三點:

Entity:使用Architecture Components時,這是一個帶注釋的類,用于描述資料庫表。

SQLite database:在裝置上,資料存儲在SQLite資料庫中。Room持久性庫為您建立和維護此資料庫。

DAO: data access object(資料通路對象)。SQL查詢到函數的映射。當您使用DAO時,您可以調用方法,而Room負責其餘的操作。

我們先建立Entity:

@Entity(tableName = "info")
public class InfoEntity {

    @PrimaryKey(autoGenerate = true)
    public int _id;

    @ColumnInfo(name = "uuid")
    private String uuid;

    private String info;

    public InfoEntity(String info) {
        uuid = UUID.randomUUID().toString();
        this.info = info;
    }

    public String getUuid() {
        return uuid;
    }

    public void setUuid(String uuid) {
        this.uuid = uuid;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return String.format("id: %s  ----> info: %s", uuid, info);
    }
}
      

@Entity(tableName = "info")

每個@Entity類代表一個表中的實體。如果希望表與名稱不同,可以在通過此處進行修改。

@PrimaryKey

每個實體都需要一個主鍵。

@NonNull

表示參數,字段或方法傳回值永遠不能為空。

 @ColumnInfo(name = "uuid")

如果希望表的列與成員字段名稱不同,可以通過此注解指定

接下來建立DAO

@Dao
public interface InfoDao {

    @Query("SELECT * FROM info")
    List<InfoEntity> getInfoList();

    @Query("SELECT * FROM info where uuid = :id")
    InfoEntity getInfoEntity(String id);

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void addInfo(InfoEntity infoEntity);

    @Delete
    void deleteInfo(InfoEntity infoEntity);

    @Update
    int update(InfoEntity infoEntity);

}      

在DAO(資料通路對象)中,指定SQL查詢并将它們與方法調用相關聯。編譯器檢查SQL并從便捷注釋生成查詢以查找常見查詢.

我們的CRUD操作全部在注解裡聲明,并且,也會檢查你的CRUD語句是否正确。

接下來就是建立Database 了.

@Database(entities = {InfoEntity.class}, version = 1, exportSchema = false)
public abstract class InfoDataBase extends RoomDatabase {

    private static InfoDataBase INSTANCE;

    public static InfoDataBase getInstance(Context context) {
        if (INSTANCE == null) {
            synchronized (InfoDataBase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(), InfoDataBase.class, "info.db").build();
                }
            }
        }
        return INSTANCE;
    }

    public abstract InfoDao getInfoDao();
}
      

1.public abstract class InfoDataBase extends RoomDatabase  {}

  建立一個public abstract類繼承自RoomDatabase 

[email protected](entities = {InfoEntity.class}, version = 1, exportSchema = false)

  将類注釋為Room資料庫,聲明屬于資料庫的實體并設定版本号。列出實體将在資料庫中建立表。exportSchema傳 true的話, 把 Scheme 導出到一個檔案夾裡面,具體的可以直接點進去看注釋。

3. public abstract InfoDao getInfoDao();

  定義使用資料庫的DAO。為每個@Dao提供抽象的“getter”方法。

到這一步,Room的代碼基本完成了。

List<InfoEntity> infoList = InfoDataBase.getInstance(DbListActivity.this).getInfoDao().getInfoList();      

可以用上面這樣的代碼去調用了。

不過,上面的代碼必須放在異步線程去調用,不然會直接崩潰,報錯:

java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.

為了友善封裝,我們可以寫一個Source

public interface InfoSource {

    interface LoadInfoListCallBack {

        void onDataNoAvailable();

        void onLoadSuccess(List<InfoEntity> list);
    }

    interface GetInfoCallBack {
        void onDataNoAvailable();

        void onLoadSuccess(InfoEntity entity);
    }

    void getInfoList(LoadInfoListCallBack callBack);

    void getInfo(String uuid, GetInfoCallBack callBack);

    void addInfo(InfoEntity entity);

    void deleteInfo(InfoEntity entity);

    void updateInfo(InfoEntity entity);

}      

然後用一個用其實作類來進行資料操作,如下:

public class CustomInfoSource implements InfoSource {

    private InfoDao dao;
    private AppExecutor appExecutor;

    public CustomInfoSource(@NonNull InfoDao dao, @NonNull AppExecutor appExecutor) {
        this.dao = dao;
        this.appExecutor = appExecutor;
    }

    @Override
    public void getInfoList(final LoadInfoListCallBack callBack) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                final List<InfoEntity> infoList = dao.getInfoList();
                appExecutor.getMainThread().execute(new Runnable() {
                    @Override
                    public void run() {
                        if (infoList == null || infoList.size() == 0) {
                            callBack.onDataNoAvailable();
                        } else {
                            callBack.onLoadSuccess(infoList);
                        }
                    }
                });

            }
        };

        appExecutor.getDiskIO().execute(runnable);
    }

    @Override
    public void getInfo(String uuid, GetInfoCallBack callBack) {

    }

    @Override
    public void addInfo(final InfoEntity entity) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                dao.addInfo(entity);
            }
        };

        appExecutor.getDiskIO().execute(runnable);
    }

    @Override
    public void deleteInfo(InfoEntity entity) {

    }

    @Override
    public void updateInfo(InfoEntity entity) {

    }
}      

這樣的話,我們再進行調用也友善:

source.getInfoList(new InfoSource.LoadInfoListCallBack() {
    @Override
    public void onDataNoAvailable() {
    }

    @Override
    public void onLoadSuccess(List<InfoEntity> infos) {
        list.addAll(infos);
        adapter.notifyDataSetChanged();
    }
});      

關于Room的簡單使用也就這樣了,附上demo位址https://github.com/mnb65482/SimpleRoomDemo

繼續閱讀