MVVM資料持久化
之前我們分別介紹了MVVM框架的悲劇,專案搭建以及網路請求,接下來在這篇文章當中,我們來聊一聊MVVM資料持久化的問題,也就是我們常說的快取
Room
Room持久庫提供了一個SQLite抽象層,讓你訪問資料庫更加穩健,提升資料庫效能。 簡介地址 developer.android.google.cn/training/da… Room在SQLite上提供了一個抽象層,以便在發揮SQLite能力的同時允許流暢的資料庫訪問,最主要的是它讓SQLiteDatabase的使用變得簡單,大大減少了重複的程式碼,並且把SQL查詢的檢查放在了編譯時。而且還可以和RxJava配合使用的十分契合。
Room有3個主要的元件
Database:
包含資料庫持有者,並充當與應用程式持久化的、關係型的資料的底層連線的主要訪問點。 用@Database註解的類應滿足以下條件: 是一個繼承RoomDatabase的抽象類。 在註釋中包含與資料庫相關聯的實體列表。 包含一個具有0個引數的抽象方法,並返回用@Dao註釋的類。 在執行時,您可以通過呼叫Room.databaseBuilder()或Room.inMemoryDatabaseBuilder()獲取資料庫例項。
Entity:
表示資料庫內的表。
DAO:
包含用於訪問資料庫的方法。
以及這三者之間的關係圖:
加入依賴
以上簡單的介紹了一下Room 下面我們著重介紹如何在我們的框架當中使用 首先加入依賴
implementation 'android.arch.persistence.room:runtime:1.1.1'
implementation 'android.arch.persistence.room:rxjava2:1.1.1'
kapt 'android.arch.persistence.room:compiler:1.1.1'
複製程式碼
看過之前文章的同學們,可以直接放在config.gradle當中,方便統一管理。
dependVersion = [
room_version : '1.1.1'
]
roomLib = [room_runtime: "android.arch.persistence.room:runtime:$dependVersion.room_version",
room_rxjave2: "android.arch.persistence.room:rxjava2:$dependVersion.room_version"
]
room = [ room: "android.arch.persistence.room:compiler:$dependVersion.room_version"]
]
roomDeps = [roomLib.values()]
roomDep = [room.values()]
複製程式碼
在專案當中引用
implementation project.ext.roomDeps
kapt project.ext.roomDep
複製程式碼
方便統一管理。 至此 我們就可以設計新的結構圖如下:
根據結構圖:
- View:Activity/Fragment
- ViewModel:使用RxJava處理資料
- Local Data:Room
- Remote Data:Retrofit
Room的使用
1.建立相應的Entity
Entity當中常用的幾個屬性
- Primary key 每個entity必須至少定義一個field作為主鍵(primary key)。即使只有一個field,你也必須用@PrimaryKey註釋這個field。如果你想讓Room為entity設定自增ID,你可以設定@PrimaryKey的autoGenerate屬性。如果你的entity有一個組合主鍵,你可以使用@Entity註解的primaryKeys屬性。
2.tableName Room預設把類名作為資料庫的表名。如果你想用其它的名稱,使用@Entity註解的tableName屬性。
3.ColumnInfo Room預設把field名稱作為資料庫表的column名。如果你想讓column有不一樣的名稱,為field新增@ColumnInfo屬性。
4.Indices 和 unique 為了提高查詢的效率,你可能想為特定的欄位建立索引。要為一個entity新增索引,在@Entity註解中新增indices屬性,列出你想放在索引或者組合索引中的欄位。 有時候,某個欄位或者幾個欄位必須是唯一的。你可以通過把@Index註解的unique屬性設定為true來實現唯一性。
5.Embedded 有時你可能想把一個entity或者一個POJOs作為一個整體看待,即使這個物件包含幾個field。這種情況下,你可以使用@Embedded註解,表示你想把一個物件分解為表的子欄位。然後你就可以像其它獨立欄位那樣查詢這些嵌入的欄位。
回到我們的專案當中,建立屬於我們的Entity:
package yang.cehome.com.mvvmdemo.model.local.dao
import android.arch.persistence.room.Entity
import android.arch.persistence.room.PrimaryKey
/**
* @author yangzc
* @data 2018/11/7 10:23
* @desc 建立Post的Entity
*
*/
@Entity
data class PostEntity(
val message: String,
@PrimaryKey
val nu: String,
val ischeck: String,
val condition: String,
val com: String,
val status: String,
val state: String
)
複製程式碼
2.建立Dao
相當於Retrofit中的api介面。
Dao負責運算元據庫的方法,也就是說我們一些運算元據庫的動作都是在這裡完成的。不同的是我們不需要這些都用Dao類當中的註解來定義查詢。
package yang.cehome.com.mvvmdemo.model.local.dao
import android.arch.persistence.room.Dao
import android.arch.persistence.room.Insert
import android.arch.persistence.room.OnConflictStrategy
import android.arch.persistence.room.Query
import io.reactivex.Single
/**
* @author yangzc
* @data 2018/11/5 17:40
* @desc PostDao
*
*/
@Dao
interface PostDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insetAll(postinfo: List<PostEntity>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun inserttWeather(postinfo: PostEntity)
@Query("SELECT * FROM postentity")
fun getWeathInfo(): Single<PostEntity>
}
複製程式碼
3.建立資料庫
相當於建立RetrofitClient物件。
我們需要建立一個AppDatabase,這個類是包含了所以的Entity以及操作他們的DAO。這個類需要繼承RoomDatabase的抽象類
package yang.cehome.com.mvvmdemo.model.local
import android.arch.persistence.room.Database
import android.arch.persistence.room.Room
import android.arch.persistence.room.RoomDatabase
import android.content.Context
import yang.cehome.com.mvvmdemo.model.local.dao.PostDao
import yang.cehome.com.mvvmdemo.model.local.dao.PostEntity
/**
* @author yangzc
* @data 2018/11/5 18:21
* @desc 包含所有Entity以及操作它們的 DAO
*
*/
@Database(entities = arrayOf(PostEntity::class), version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun WeatherDao(): PostDao
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context): AppDatabase =
INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
private fun buildDatabase(context: Context) =
Room.databaseBuilder(context.applicationContext,
AppDatabase::class.java, "app.db")
.build()
}
}
複製程式碼
Ok 至此Room整合完成