Android Jetpackアーキテクチャコンポーネント(七)Room使用編
27432 ワード
前言の前のいくつかの編はLifecycle、LiveData、ViewModelを説明して、前のいくつかの編の敷居があって、私達が今日説明するRoomを引き出すことができて、Roomは1つのデータベースのアクセスコンポーネントで、SqLiteデータベースに対して友好的なパッケージをして、私達にコードする時、論理の部分を重視するだけでいいことができて、データベースはRoomに渡して流暢なアクセスに行きます.
Room使用手順>Githubプロジェクトアドレス 1依存 を追加2 エンティティクラス注釈 1 tableName:データベース内のテーブル名を設定します.この値を設定しない場合、デフォルトはクラスの名前です. 2 indices:インデックスを設定します.インデックスは、データベース・テーブルのデータ・アクセス速度を向上させるために使用されます.単一のカラム・インデックスと組合せインデックスがあります. 3 inheritSuperIndices:親のインデックスが現在のクラスに自動的に継承されるかどうか. 4 primaryKeys:プライマリ・キーを設定します.このプライマリ・キーの値がこのオブジェクトを一意に決定できる場合は、プライマリ・キーを1つだけ設定できます.フィールド値がオブジェクトを一意に決定できない場合は、 5 foreignKeys:外部キー、すなわちFOREGN KEYコンストレイントを設定します.Sqliteデータベースはリレーショナル・データベースに属するため、テーブル間にリレーショナルが存在するため、このプロパティ値は2つのフォーム間の関係を関連付けるために使用されます.以上のように 6 ignoredColumns:無視されたフィールド.
クラスでは、 には、さらに
3宣言 という コードを同期すると、
4宣言 は、 このクラスは
5取得データ WorkManagerの使用はこのセクションの重点ではありません.使用は簡単ですが、ソース分析は複雑です.後で単独で説明します.
6最終使用 上記のコードを呼び出すと、私たちのデータとライフサイクルが結合され、データが変化すると、UIを更新するコードがすぐにコールバックされ、私たちの目的を達成します. ここではViewModelのコードを省略しています.ここでViewModelのコードを貼ると、
Room使用手順>Githubプロジェクトアドレス
build.gradle {
apply plugin: 'kotlin-kapt'
dependencies {
kapt "androidx.room:room-compiler:$rootProject.roomVersion"
implementation "androidx.room:room-runtime:$rootProject.roomVersion"
}
}
Entity
エンティティークラス@Entity(tableName = "apps")
data class AppEntity(
@ColumnInfo(name = "packageName") @PrimaryKey val packageName: String,
@ColumnInfo(name = "app_id") val id: Int,
@ColumnInfo(name = "versionCode") val versionCode: String,
@ColumnInfo(name = "versionLabel") val versionLabel: String,
@ColumnInfo(name = "versionName") val versionName: String,
@ColumnInfo(name = "description") val description: String,
@ColumnInfo(name = "icon") val icon: String)
@Entity(tableName = "comments",
foreignKeys = [
ForeignKey(entity = AppEntity::class,
parentColumns = ["packageName"],
childColumns = ["packageName"],
onDelete = ForeignKey.CASCADE)
],
indices = [Index("packageName")])
class CommentEntity(@PrimaryKey(autoGenerate = true) val id: Int = 0,
val packageName: String,
val comment: String = "this is comment for $packageName")
を作成Entity
を使用してマークします.多くのプロパティがあります.primaryKeys
で配列を設定できる複合プライマリ・キーが必要です.さらに、各Entity
はプライマリ・キーを設定する必要があります.親と子がプライマリ・キーを設定している場合、子のプライマリ・キーは親のプライマリ・キーを上書きします.CommentEntity
には、AppEntity
のpackageNameという外部キーが設定されています.ColumnInfo
注記も使用されます.属性値name
は、データベースに格納されているテーブル内のフィールドの値をマークするために使用されます.設定しない場合は、宣言されたフィールドの値がデフォルトです.Embedded
があり、ネストされたオブジェクトを表しています.クラスAを別のクラスBに入れることができ、BでAに注釈Embedded
を使用するだけで、BはAのすべての属性値を正常に使用することができます.Dao
オブジェクト@Dao
interface AppsDao {
@Query("SELECT * FROM apps")
fun loadApps(): LiveData<List<AppEntity>>
@Query("SELECT * FROM apps WHERE packageName = :packageName")
fun loadApp(packageName: String): LiveData<AppEntity>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(apps: List<AppEntity>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(app: AppEntity)
@Delete
fun delete(app: AppEntity)
@Update
fun update(app: AppEntity)
}
Dao
オブジェクトの宣言はinterface
で修飾しなければならない.また、4種類の添削添削を提供した注釈を見ると、クエリの注釈だけは少量のSQL文を入力する必要があり、インタフェースの戻り値を定義することはLiveDataなどの観察可能なデータでもあり、操作が非常に便利である.generated
にxxx_Impl.java
オブジェクトが生成され、宣言したインタフェースメソッドが実装され、自分で処理する必要はありません.Database
オブジェクト@Database(entities = [AppEntity::class, CommentEntity::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun appsDao(): AppsDao
abstract fun commentsDao(): CommentsDao
companion object {
private const val DATABASE_NAME = "forward-db"
private val executors: ExecutorService = Executors.newSingleThreadExecutor()
@Volatile
private var instance: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
return instance ?: synchronized(this) {
instance ?: buildDatabase(context.applicationContext).also {
instance = it
}
}
}
private fun buildDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME)
.addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
executors.execute {
Thread.sleep(3000)
val request: OneTimeWorkRequest = OneTimeWorkRequestBuilder<AppsWorker>().build()
WorkManager.getInstance(context).enqueue(request)
}
}
})
.build()
}
}
}
Database
注釈を使用して、私たちが宣言したすべてのEntity
オブジェクト、バージョン番号version
、およびSchema
などの属性値をエクスポートするかどうかを注釈します.RoomDatabase
を継承し、一般的にこのクラスは単例の形式で使用される.さらに、
を使用してオブジェクトを作成し、データベースに格納されたonCreate
メソッドのうち、WorkManager
を使用して、以下に示すように、データの取得をどこかに配置することができます.class AppsWorker(context: Context, workerParameters: WorkerParameters)
: CoroutineWorker(context, workerParameters) {
private val TAG by lazy {
AppsWorker::class.java.simpleName
}
override suspend fun doWork(): Result = coroutineScope {
try {
applicationContext.assets.open("apps.json").use {
JsonReader(it.reader()).use { reader ->
val appsType = object : TypeToken<List<AppEntity>>() {}.type
val appsList: List<AppEntity> = Gson().fromJson(reader, appsType)
val comments = DataGenerator.getComments(appsList)
val appsDao = RepositoryProvider.providerAppsRepository(applicationContext)
val commentDao = RepositoryProvider.providerCommentsRepository(applicationContext)
appsDao.insertAll(appsList)
commentDao.insertAll(comments)
}
Result.success()
}
} catch (e: Exception) {
Result.failure()
}
}
private fun insertData(database: AppDatabase, apps: List<AppEntity>, comments: List<CommentEntity>) {
database.runInTransaction {
database.appsDao().insertAll(apps)
database.commentsDao().insertAll(comments)
}
}
}
viewModel.apps.observe(viewLifecycleOwner, Observer {
if (it.isNullOrEmpty()) {
binding.loading = true
} else {
binding.loading = false
adapter.setList(it)
}
binding.executePendingBindings()
})
Factory
とRepository
に関するコードがたくさん貼られなければなりません.具体的なソースコードはGithubプロジェクトのアドレスに行って見ることができます.