数据库工具:Room

Room结构

导入依赖

app的build.gradle中开启kapt:

apply plugin: 'kotlin-kapt'

并导入以下依赖:

def room_version = '2.2.4'
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor
// Test helpers
testImplementation "androidx.room:room-testing:$room_version"
kapt 'android.arch.persistence.room:compiler:1.1.1'
implementation 'androidx.recyclerview:recyclerview:1.1.0' //注意:对于基于 Kotlin 的应用,请确保使用 kapt 而不是 annotationProcessor。您还应添加 kotlin-kapt 插件。

基础三大件:Entity,Dao,Database

Entity:数据库的结构

语法
使用@Entity注解Entity类
使用@PrimaryKey(autoGenerate = true),@ColumuInfo(name = "")注解键
示例
@Entity(tableName = "word_table")     //数据库结构
data class Word (
@PrimaryKey(autoGenerate = true)
var id: Int,
@ColumnInfo(name = "english")
var word: String,
@ColumnInfo(name = "chinese")
var chineseMeaning: String
)

Dao:数据库的操作

语法
使用 @Dao注解接口
使用 @Insert,@Update,@Delete,@Query("DELETE FROM WORD"),@Query("SELECT * FROM WORD ORDER BY ID DESC") 等注解数据库操作
示例
@Dao        //数据库操作
interface WordDao {
@Insert
fun insertWords(vararg words: Word) @Update
fun updateWords(vararg words: Word) @Delete
fun daleteWords(vararg words: Word) @Query("DELETE FROM WORD")
fun deleteAllWords() @Query("SELECT * FROM WORD ORDER BY ID DESC")
fun getAllWords() : LiveData<List<Word>> //使用LiveData,观测数据改变并自动
}

Database:数据库工具类

语法
使用 @Database(entities = [com.example.roomtest.Word::class], version = 1, exportSchema = false) 注解类
尽量使用抽象类并且使用单例模式
示例
@Database(entities = [com.example.roomtest.Word::class], version = 1, exportSchema = false)
//获取数据库实体
abstract class WordDatabase : RoomDatabase() {
abstract fun getWordDao() : WordDao /**
* 单例数据库
*/
companion object {
private var instance: WordDatabase? = null
@Synchronized
fun get(context: Context): WordDatabase {
if (instance == null) {
instance = Room.databaseBuilder(context.applicationContext,
WordDatabase::class.java, "word_database")
.build()
}
return instance!!
}
}
}

进阶

一、使用ViewModel

1,导入ViewModel模板
2,示例
class WordViewModel(application: Application) : AndroidViewModel(application) {
var wordDao: WordDao
var allWordLive: LiveData<List<Word>> init {
val wordDatabase = WordDatabase.get(application)
wordDao = wordDatabase.getWordDao()
allWordLive = wordDao!!.getAllWords()
} fun insertWords(vararg words: Word) {
InsertAsyncTask(wordDao!!).execute(*words)
} fun clearWords() {
ClearAsyncTask(wordDao!!).execute()
} inner class InsertAsyncTask(val wordDao: WordDao) : BaseAsyncTask(wordDao) {
override fun doInBackground(vararg params: Word): Void? {
wordDao.insertWords(*params)
return null
}
}
inner class UpdateAsyncTask(val wordDao: WordDao) : BaseAsyncTask(wordDao) {
override fun doInBackground(vararg params: Word): Void? {
return null
}
}
inner class DeleteAsyncTask(val wordDao: WordDao) : BaseAsyncTask(wordDao) {
override fun doInBackground(vararg params: Word): Void? {
return null
}
}
inner class ClearAsyncTask(val wordDao: WordDao) : BaseAsyncTask(wordDao) {
override fun doInBackground(vararg params: Word): Void? {
wordDao.deleteAllWords()
return null
}
} }

以上ViewModel将数据的操作与使用放在一起,还可以继续分层:将数据的使用剥离出去

二、使用仓库Reposity访问数据

示例
/**
* 数据访问
*/
class WordRepository(val context: Context) {
private var allWordsLive : LiveData<List<Word>>
private var wordDao : WordDao init {
val wordDatabase = WordDatabase.get(context)
wordDao = wordDatabase.getWordDao()
allWordsLive = wordDao.getAllWords()
} fun insertWords(vararg words: Word) {
InsertAsyncTask(wordDao!!).execute(*words)
} fun clearWords() {
ClearAsyncTask(wordDao!!).execute()
} inner class InsertAsyncTask(val wordDao: WordDao) : BaseAsyncTask(wordDao) {
override fun doInBackground(vararg params: Word): Void? {
wordDao.insertWords(*params)
return null
}
} inner class ClearAsyncTask(val wordDao: WordDao) : BaseAsyncTask(wordDao) {
override fun doInBackground(vararg params: Word): Void? {
wordDao.deleteAllWords()
return null
}
}
}

改造后的ViewModel:

class WordViewModel(application: Application) : AndroidViewModel(application) {
private val wordDao: WordDao
var allWordLive: LiveData<List<Word>> init {
val wordDatabase = WordDatabase.get(application)
wordDao = wordDatabase.getWordDao()
allWordLive = wordDao!!.getAllWords()
} fun insertWords(vararg words: Word) {
WordRepository(getApplication()).insertWords(*words)
} fun clearWords() {
WordRepository(getApplication()).clearWords()
}
}

三、升级数据库

Room.databaseBuilder(context.applicationContext,
WordDatabase::class.java,
"word_database")
.fallbackToDestructiveMigration() //破坏式升级:升级版本后清空原有内容
.addMigrations(MIGRATION_1_2) //无痛改变
.build() val MIGRATION_1_2 : Migration = object : Migration(1, 2) { //类的参数分别为新旧数据库的版本号
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("") //使用SQL语句进行数据库操作
}
}

项目的其他代码

基累BaseAsyncTask:

open class BaseAsyncTask(private val wordDao: WordDao) : AsyncTask<Word, Void, Void>() {
override fun doInBackground(vararg words: Word): Void? {
return null
}
}

Acitvity:

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import java.lang.StringBuilder class MainActivity : AppCompatActivity() { private lateinit var insert: Button
private lateinit var update: Button
private lateinit var delete: Button
private lateinit var clear: Button
private lateinit var content : TextView private lateinit var wordViewModel: WordViewModel override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) insert = findViewById(R.id.insert)
update = findViewById(R.id.update)
delete = findViewById(R.id.delete)
clear = findViewById(R.id.clear)
content = findViewById(R.id.content) wordViewModel = ViewModelProviders.of(this)[WordViewModel::class.java] wordViewModel.allWordLive.observe(this, Observer {
var text = StringBuilder()
for (x in it) {
text.append(x.id).append(":").append(x.word).append("=").append(x.chineseMeaning).append("\n")
}
content.text = text.toString()
}) insert.setOnClickListener {
var word1 = Word(0, "Hello", "你好")
var word2 = Word(0, "World", "世界")
wordViewModel.insertWords(word1, word2)
} clear.setOnClickListener {
wordViewModel.clearWords()
}
}
}

xml布局:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"> <androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.6" /> <ScrollView
android:id="@+id/scrollView2"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"> <TextView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textSize="24sp" />
</ScrollView> <androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" /> <androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.8" /> <Button
android:id="@+id/insert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="insert"
app:layout_constraintBottom_toTopOf="@+id/guideline3"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline"
app:layout_constraintVertical_bias="0.52" /> <Button
android:id="@+id/update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="update"
app:layout_constraintBottom_toTopOf="@+id/guideline3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="@+id/guideline"
app:layout_constraintVertical_bias="0.52" /> <Button
android:id="@+id/clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="clear"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline3" /> <Button
android:id="@+id/delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="delete"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="@+id/guideline3" />
</androidx.constraintlayout.widget.ConstraintLayout>

懒加载控件:Paging

声明依赖

def paging_version = "2.1.1"
implementation "androidx.paging:paging-runtime:$paging_version" // For Kotlin use paging-runtime-ktx
// alternatively - without Android dependencies for testing
testImplementation "androidx.paging:paging-common:$paging_version" // For Kotlin use paging-common-ktx
// optional - RxJava support
implementation "androidx.paging:paging-rxjava2:$paging_version" // For Kotlin use paging-rxjava2-ktx

Paging + Room + RecyclerView

数据类型

Dao中,数据使用DataSource.Factory<Key, Value>格式

@Dao
interface StudentDao {
@Query("SELECT * FROM student_table ORDER BY id")
fun getAllStudents() : DataSource.Factory<Int, Student>
}

RecycleView的适配器

改用PagedListAdapter<数据类型, Holder>:

class MyPagedAdapter : PagedListAdapter<Student, MyViewHolder>(DIFF_CALLBACK) {
companion object {
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Student>() {
override fun areItemsTheSame(oldItem: Student, newItem: Student): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Student, newItem: Student):Boolean {
return oldItem.studentNumber == newItem.studentNumber
}
}
} override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(view)
} override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
} class MyViewHolder(itemView: View) : ViewHolder(itemView) {
}
}

装配数据

private lateinit var studentDao: StudentDao						//Dao类
private lateinit var studentDatabase : StudentDatabase //数据库类
private lateinit var pagedAdapter: MyPagedAdapter //适配器类
private lateinit var allStudentsLivePaged : LiveData<PagedList<Student>> //分页数据管理 override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) pagedAdapter = MyPagedAdapter()
list.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
list.adapter = pagedAdapter studentDatabase = StudentDatabase.getInstance(this)
studentDao = studentDatabase.getStudentDao() //第二个参数为一次加载数据的个数
allStudentsLivePaged = LivePagedListBuilder(studentDao.getAllStudents(), 2).build()
}

AndroidJetpack数据处理之数据库Room和懒加载Paging的更多相关文章

  1. hibernate懒加载(转载)

    http://blog.csdn.net/sanjy523892105/article/details/7071139 懒加载详解 懒加载为Hibernate中比较常用的特性之一,下面我们详细来了解下 ...

  2. Hibernate中的一级缓存、二级缓存和懒加载(转)

    1.为什么使用缓存 hibernate使用缓存减少对数据库的访问次数,从而提升hibernate的执行效率.hibernate中有两种类型的缓存:一级缓存和二级缓存. 2.一级缓存 Hibenate中 ...

  3. Hibernate中的一级缓存、二级缓存和懒加载

    1.为什么使用缓存 hibernate使用缓存减少对数据库的访问次数,从而提升hibernate的执行效率.hibernate中有两种类型的缓存:一级缓存和二级缓存. 2.一级缓存 Hibenate中 ...

  4. Hibernate第八篇【懒加载】

    前言 前面在使用Hibernate的时候就提及过了懒加载,但没有好好地说明具体的说明究竟是怎么回事-本博文主要讲解懒加载 什么是拦截器以及为什么要使用懒加载? 懒加载就是当使用数据的时候才去获取数据. ...

  5. Hibernate懒加载解析

    Hibernate懒加载解析 在Hibernate框架中,当我们要访问的数据量过大时,明显用缓存不太合适, 因为内存容量有限 ,为了减少并发量,减少系统资源的消耗,这时Hibernate用懒加载机制来 ...

  6. @Basic表示一个简单的属性 懒加载,急加载

    5.@Basic(fetch=FetchType,optional=true) 可选 @Basic表示一个简单的属性到数据库表的字段的映射,对于没有任何标注的getXxxx()方法,默认 即为 @Ba ...

  7. hibernate懒加载

    Hibernate懒加载解析 hibernatejoinsession数据库sqlobject Hibernate懒加载解析 在Hibernate框架中,当我们要访问的数据量过大时,明显用缓存不太合适 ...

  8. 四十二:数据库之SQLAlchemy之数据查询懒加载技术

    懒加载在一对多,或者多对多的时候,如果要获取多的这一部分的数据的时候,通过一个relationship定义好对应关系就可以全部获取,此时获取到的数据是list,但是有时候不想获取全部数据,如果要进行数 ...

  9. 在ThinkPHP框架(5.0.24)下引入Ueditor并实现向七牛云对象存储上传图片同时将图片信息保存到MySQL数据库,同时实现lazyload懒加载

    这是我花了很多天的时间才得以真正实现的一组需求. 文章后面有完整Demo的GitHub链接. 一. 需求描述 1. 应用是基于ThinkPHP5开发的: 2. 服务器环境是LNMP,PHP版本是7.2 ...

随机推荐

  1. English Study!

    As you konw, education is a top priority for us !  When the times abandon you, they don't even call ...

  2. TS中 使用deprecated 实现对方法的迭代弃用

    在日常开发中,我们会定义大量方法函数来提供给业务调用,可随着时间与业务的推进, 有些方法可能不切合当下需求, 或将被逐步废弃并替换到新的方法中, 例如 框架中 部分生命周期的废弃. 此时作为开发者就很 ...

  3. 版本号是通过import合并而来的,不是继承来的

  4. 'Rem EverythingAutoSetup.VBS 安装Everything的VBS脚本 2019年11月25日写

    'Rem EverythingAutoSetup.VBS 安装Everything的VBS脚本 2019年11月25日写 'Rem Everything是voidtools开发的一款本地NTFS文件和 ...

  5. 配置多个git用的ssh key

    参考 http://www.sail.name/2018/12/16/ssh-config-of-mac/ 有一点注意 Host 的名字和 HostName改为一致. 因为从git仓库复制的地址是全程 ...

  6. netty系列之:中国加油

    目录 简介 场景规划 启动Server 启动客户端 消息处理 消息处理中的陷阱 总结 简介 之前的系列文章中我们学到了netty的基本结构和工作原理,各位小伙伴一定按捺不住心中的喜悦,想要开始手写代码 ...

  7. 聊聊 PC 端自动化最佳方案 - WinAppDriver

    1. 前言 大家好,我是安果! 一提到自动化,可能大家想到的是 App 端的 Appium.Airtest.AutoJS,亦或是 Selenium.Puppeteer.Cypress 等 Web 端的 ...

  8. netty系列之:自动重连

    目录 简介 使用netty建立连接 自动重连接的原理 模拟自动重连 总结 简介 我们在使用客户端和服务器端连接的过程中,可能会因为各种问题导致客户端和服务器的连接发生中断,遇到这种情况,一般情况下我们 ...

  9. 建立局域网内使用的CentOS7源

    建立局域网内使用的CentOS7源 by 无若    1. 在CentOS下建立匿名的FTP访问服务 CentOS 7下安装配置pure-ftpd,并使用匿名用户登录 Pure-FTPd是Linux上 ...

  10. Logback 快速入门 / 使用详解

    官方文档: http://logback.qos.ch/manual/index.html 一.简介 Java 开源日志框架,以继承改善 log4j 为目的而生,是 log4j 创始人 Ceki Gü ...