標籤雲

搜尋此網誌

2018/08/07

Room Persistence Library 簡單介紹

使用 Room 需要在 app 的 build.gradle 中增加 dependencies

dependencies {
    def room_version = "1.1.1"

    implementation "android.arch.persistence.room:runtime:$room_version"
    annotationProcessor "android.arch.persistence.room:compiler:$room_version" // use kapt for Kotlin

    // optional: RxJava support for Room
    implementation "android.arch.persistence.room:rxjava2:$room_version"
    // optional: Guava support for Room, including Optional and ListenableFuture
    implementation "android.arch.persistence.room:guava:$room_version"
    // Test helpers
    testImplementation "android.arch.persistence.room:testing:$room_version"
}

Room 有三種主要元件

- Entity: 對應到 database 的 table

- DAO: 擁有存取 database 資料的 method

- Database: 是主要存取點與 db 的持有者, 需要滿足以下要件
使用 @Database 這個 annotation 並且在裡面宣告 Entities 的 list 來定義包含的 table
繼承 RoomDatabase 的 abstract class
擁有無參數的 abstract method 可以 return 用 @Dao 標記的 Data Access Object

另外, 由於 Database 是比較耗資源的類別, 所以建議是使用 singleton 模式來獲得實體

所以一個 Database 大概會長這樣
@Database(entities = {Alarm.class}, version = 1, exportSchema = false)
public abstract class XXXXXDB extends RoomDatabase {
 public static final String DB_NAME = "xxxxx_db";

 private static XXXXXDB INSTANCE;

 public static XXXXXDB getInstance(final Context context){
  if(INSTANCE == null){
   synchronized (AlarmDB.class) {
    if(INSTANCE == null) {
     INSTANCE = Room.databaseBuilder(context, XXXXXDB.class, DB_NAME).build();
    }
   }
  }
  return INSTANCE;
 }

 public static void destroyInstance() {
  if(INSTANCE != null){
   INSTANCE.close();
  }
  INSTANCE = null;
 }


 public abstract XXXXXDao xxxxxDao();

}

而 Data Access Object 則會長得像是這樣
@Dao
public interface XXXXXDao {
 @Query("SELECT * FROM "+XXXXX.TABLE_NAME+" ORDER BY "+XXXXX.Col.TIME+" DESC" )
 List queryXXXXXs();

 @Query("SELECT * FROM "+XXXXX.TABLE_NAME+" WHERE "+XXXXX.Col.ID+" = :id")
 Alarm queryXXXXX(long id);

 @Query("SELECT * FROM "+XXXXX.TABLE_NAME+" WHERE "+XXXXX.Col.TIME+" BETWEEN :afterTheTime AND :beforeTheTime")
 List queryXXXXXs(long afterTheTime, long beforeTheTime);

 //return long (the rowId)
 @Insert(onConflict = OnConflictStrategy.REPLACE)
 long insertXXXXX(XXXXX x);

 @Delete
 void deleteXXXXX(XXXXX x);
}

最後是 Entity object 的簡單範例
@Entity(tableName = XXXXX.TABLE_NAME)
public class XXXXX {
 private static final String TAG = XXXXX.class.getSimpleName();

 public static final String TABLE_NAME = "XXXXXs";

 public class Col {
  public static final String ID = "id";
  public static final String TARGET_DEVICE = "target_device_id";
  public static final String ACTION = "action";
  public static final String TIME = "time";
  public static final String TYPE = "type";
  public static final String CONTENT = "content";
 }
 public class Value {
  public static final String ACTION_AAA = "aaa";
  public static final String ACTION_BBB = "bbb";
 }

 @PrimaryKey
 @ColumnInfo(name= Col.ID)
 public long id;

 @ColumnInfo(name= Col.TARGET_DEVICE)
 public String targetDeviceId;

 @ColumnInfo(name= Col.ACTION)
 public String action;

 @ColumnInfo(name= Col.TIME)
 public long time;

 @ColumnInfo(name= Col.TYPE)
 public int type;

 @ColumnInfo(name= Col.CONTENT)
 public String content;

 @Ignore
 private int[] myInts;

 public Alarm() { }

}

另外由於檔案存取不允許在主 thread 進行
所以建議在 AsyncTask 或是 IntentService 裡面操作


相關資料:
Android Developers: Adding Components to your Project#Room
Google Developers Codelabs: Android Room with a View
Android Developers: Save data in a local database using Room

沒有留言: