JetPack Room使用

2022-05-19  本文已影响0人  Sky_Blue
文章内容包括:
项目依赖
plugins {
    ...
    id 'kotlin-kapt'
}
dependencies {
    ...
    // room
    def room_version = "2.4.2"
    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version"
}

Room介绍

Room 谷歌官网介绍
Room 持久性库在 SQLite 上提供了一个抽象层,
相对于SQLiteOpenHelper等传统方法,使用Room操作SQLite有以下优势:

  1. 编译期的SQL语法检查
  2. 开发高效,避免大量模板代码
  3. API设计友好,容易理解
  4. 可以LiveData关联,具备LiveData Lifecycle 的所有魅力

Room的使用,主要涉及以下3个组件

一、Entity使用(相当于建一张表)
/**
 * 实体类,相当表创建一张表
 * 1. 版本2时,添加字段phone
 * 2. 版本3时,删除字段pwd
 */
@Entity(tableName = "student")
data class Student(
    @ColumnInfo(name = "name") var name: String,
/*    @ColumnInfo(name = "pwd") var pwd: String,*/
    @ColumnInfo(name = "phone") var phone: String = ""
) {
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "sid")
    var sid: Int = 0
}
二、DAO使用(通过DAO访问数据库操作表)
/**
 * 数据库访问对象
 */
@Dao
interface StudentDao {

    // 增
    @Insert
    fun insert(vararg students: Student)

    // 删
    @Delete
    fun delete(vararg students: Student)

    // 清空表数据
    @Query("delete from student")
    fun deleteAll()

    // 根据id列表查询
    @Query("delete from student where sid in(:sids)  ")
    fun deleteStudentByIds(vararg sids: Int)

    // 改
    @Update
    fun update(vararg students: Student)

    // 改id改名称
    @Query("update student set name=:name where sid=:sid ")
    fun update(name: String, sid: Int)


    // 根据sid 查询一个
    @Query("select * from student where sid=:sid")
    fun query(sid: Int): Student

    // 根据sids查询
    @Query("select * from student where sid in(:sids)")
    fun queryAll(vararg sids: Int): List<Student>

    // 查询所有,与LiveData结合使用
    @Query("select * from student")
    fun queryAll(): LiveData<List<Student>>

}
三、Database使用(数据库初始化)
/**
 * 本地数据库-->可以存放多张表
 */
@Database(
    entities = [Student::class],
    version = 3,
    exportSchema = false
)
abstract class AppDataBase : RoomDatabase() {
    // Student数据访问对象
    abstract fun getStudentDao(): StudentDao


    companion object {
        @Volatile
        private var dataBase: AppDataBase? = null
        private val countDownLatch = CountDownLatch(1)

        /**
         * 1. 在Application先调用init方法
         * 2. 获取数据库,会阻塞
         */
        fun getAppDataBase(): AppDataBase {
            if (dataBase == null) {
                countDownLatch.await()
            }
            return dataBase!!
        }

        // 初始化
        fun init(context: Context) {
            // thread别写了Thread ,如果写就这样写Thread{}.start()
            thread {
                try {
                    dataBase = Room.databaseBuilder(
                        context.applicationContext,
                        AppDataBase::class.java,
                        "app_database"
                    ).addMigrations(MIGRATION_1_2,MIGRATION_2_3)
                        .build()
                } finally {
                    // 计数一次
                    countDownLatch.countDown()
                }
            }
        }

        // 数据库升级:student表 添加一列 phone
        private val MIGRATION_1_2 = object : Migration(1, 2) {
            override fun migrate(database: SupportSQLiteDatabase) {
                // student表 添加一列 phone
                var sql = "alter table student add column phone TEXT not null default ''"
                database.execSQL(sql)
            }
        }

        // ROOM 是不能降级的,我非要删除一个字段,却要保证数据的稳定性,这个是特殊情况
        // 特殊手法降级
        private val MIGRATION_2_3: Migration = object : Migration(2, 3) {
            override fun migrate(database: SupportSQLiteDatabase) {
                // 实现删除字段 pwd
                // SQL 四步法
                // 1.先建立临时表
                database.execSQL("create table stu_temp (sid integer primary key not null," +
                        "name TEXT not null default '',phone TEXT not null default '')")

                // 2.复制之前表的数据
                database.execSQL("insert into stu_temp(sid,name,phone) select sid,name,phone from student")

                // 3.删除student 旧表
                database.execSQL("drop table student")

                // 4.修改 临时表 为 新表 student
                database.execSQL("alter table stu_temp rename to student")
            }
        }
    }
}

四、创建Student仓库,提供外部使用

/**
 * Student仓库
 */
object StudentRepository {
    private var dao = AppDataBase.getAppDataBase().getStudentDao()

    // 这里是提供一份观察数据
    var students = queryAll()

    // 增
    fun insert(vararg students: Student) {
        dao.insert(*students)
    }

    // 删
    fun delete(vararg students: Student) {
        dao.delete(*students)
    }

    fun deleteAll() {
        dao.deleteAll()
    }


    // 根据ID删除
    fun deleteStudentByIds(vararg sids: Int) {
        dao.deleteStudentByIds(*sids)
    }

    // 改
    fun update(vararg students: Student) {
        dao.update(*students)
    }

    // 改
    fun update(name: String, sid: Int) {
        dao.update(name, sid)
    }

    // 根据sid 查询一个
    fun query(sid: Int): Student {
        return dao.query(sid)
    }

    // 根据sids查询
    fun queryAll(vararg sids: Int): List<Student> {
        return dao.queryAll(*sids)
    }

    // 查询所有,与LiveData结合使用
    open fun queryAll(): LiveData<List<Student>> {
        return dao.queryAll()
    }

}
五、结合ViewModel使用
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="vm"
            type="com.boardour.viewmodel.activity.student.StudentDataBaseViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="15dp">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintBottom_toTopOf="@id/ll_bottom"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <LinearLayout
            android:id="@+id/ll_bottom"
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:orientation="horizontal"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent">

            <Button
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:onClick="@{()->vm.insert()}"
                android:text="增" />

            <Button
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_marginLeft="3dp"
                android:layout_weight="1"
                android:onClick="@{()->vm.delete()}"
                android:text="删" />

            <Button
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_marginLeft="3dp"
                android:layout_weight="1"
                android:onClick="@{()->vm.update()}"
                android:text="改" />

            <Button
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_marginLeft="3dp"
                android:layout_weight="1"
                android:onClick="@{()->vm.query()}"
                android:text="查" />
        </LinearLayout>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
/**
 * 数据库测试类
 */
class StudentDataBaseActivity : ViewModelActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // DataBinding
        val binding = DataBindingUtil.setContentView<ActivityStudentDatabaseBinding>(
            this, R.layout.activity_student_database
        )
        binding.vm = getViewModel(StudentDataBaseViewModel::class.java)
        binding.lifecycleOwner = this

        // UI相关
        binding.recyclerView.layoutManager =
            LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true)
        val adapter = object : XQuickAdapter<Student>(this, R.layout.item_recycler_database) {
            override fun convert(holder: XQuickViewHolder, item: Student, position: Int) {
                holder.setText(R.id.name, item.name)
                holder.setText(R.id.pwd, item.phone)
                holder.setText(R.id.sid, "${item.sid}")
            }
        }
        binding.recyclerView.adapter = adapter
        // 观察数据库Student表的变化
        StudentRepository.students.observe(this) {
            adapter.replaceAll(it)
            binding.recyclerView.scrollToPosition(it.size - 1)
        }
        
    }
}
open class ViewModelActivity : AppCompatActivity() {
    /**
     * 子类用
     */
    fun <T : ViewModel> getViewModel(clazz: Class<T>): T {
        return ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(clazz)
    }

    /**
     * 子类用
     */
    fun <T : ViewModel> getAndroidViewModel(clazz: Class<T>): T {
        return ViewModelProvider(
            this,
            ViewModelProvider.AndroidViewModelFactory.getInstance(application)
        )
            .get(clazz)
    }
}
/**
 * 结合ViewModel使用
 */
class StudentDataBaseViewModel : ViewModel() {

    fun insert() {
        // 新增
        thread {
            // 版本1 StudentRepository.insert(Student("name",  "pwd"))
            // 版本2 StudentRepository.insert(Student("name",  "pwd","phone"))
            // 版本3
            StudentRepository.insert(Student("name",  "1366"))
        }
    }

    fun delete() {
        // 删除所有
        thread {
            StudentRepository.deleteAll()
        }
    }

    fun update() {
        thread {
            StudentRepository.update("Lven", 6)
        }
    }

    fun query() {
        thread {
            var stu = StudentRepository.query(6)
            if (stu != null) {
                Log.e("TAG", stu.name)
            }
        }
    }
}
最终测试结果
测试结果.png
上一篇下一篇

猜你喜欢

热点阅读