前排叠甲:同上一篇
走到这一步之后,我们不再新增简单的页面和跳转,从开始我们就忽视了数据的问题,从这里开始将给软件添加一个本地数据库。毕竟写小说的软件说实话并不适合建立网上数据库,这样成本比较高,有泄露风险。做一个本地数据库的话则可以很好的解决这些问题。
当然,本地数据库则无法在其他端查看,软件卸载时会随着软件清除其中数据,因此以后的数据导入和导出也很重要!
1、Room数据库的引入
说实话我并不知道哪个数据库更方便快捷,只是这个Room数据库用起来比较方便,所以就用它了。
首先在gradle(Module:app)中引入依赖:
dependencies {
implementation("androidx.room:room-runtime:2.5.1")
ksp("androidx.room:room-compiler:2.5.1")
implementation("androidx.room:room-ktx:2.5.1")
}
这时候,ksp应该会报错,
因为编译器本身并未添加ksp插件,因此需要进行一系列操作:
1.1、在gradle(Module:app)中开头位置引入id
plugins {
id("com.google.devtools.ksp")
}
1.2、修改编译版本
将原来的1.8改为17,如下:
修改前:
修改后:
1.3在gradle(Project)中添加插件【注意是另外一个文件】
plugins {
id("com.google.devtools.ksp") version "1.8.10-1.0.9" apply false
}
1.4在settings文件中添加国内镜像网址(为了防止以后有些包下载速度太慢,不加应该也行,反正我加了)
原来:
添加后:
代码如下:
maven { url = uri( "https://maven.aliyun.com/repository/public") }
maven { url = uri( "https://maven.aliyun.com/repository/google" )}
maven { url = uri( "https://maven.aliyun.com/repository/gradle-plugin") }
google()
mavenCentral()
gradlePluginPortal()
maven { url = uri( "https://maven.google.com") }
以上步骤完成后点击同步,完成Room数据库依赖包的安装。
2、新建数据类Entities
首先新建database的文件夹
之后新建Entities文件,用来存放不同的数据类:
@Entity(tableName = "fictionData")
data class Book(
@PrimaryKey(autoGenerate = true)
val numberId: Int = 0,
@ColumnInfo(name = "fiction_id")
var fictionId: Int = 0,
@ColumnInfo(name = "fiction_name")
var fictionName: String? = null,
)
@Entity(tableName = "chapterData")
data class Chapter(
@PrimaryKey(autoGenerate = true)
val selfId: Int = 0,
@ColumnInfo(name = "fiction_id")
var fictionId: Int = 0,
@ColumnInfo(name = "chapter_id")
var chapterId: Int = 0,
@ColumnInfo(name = "chapter_Name")
var chapterName: String? = "null",
@ColumnInfo(name = "chapter_text")
var chapterText: String? = "null",
@ColumnInfo(name = "last_update_time")
var lastUpdateTime: String = ""
)
@Entity(tableName = "dictionaryData")
data class Dictionary(
@PrimaryKey(autoGenerate = true)
val selfId: Int = 0,
@ColumnInfo(name = "fiction_id")
var fictionId: Int = 0,
@ColumnInfo(name = "chapter_id")
var chapterId: Int = 0,
@ColumnInfo(name = "dic_item_id")
var dicItemId: Int = 0,
@ColumnInfo(name = "dic_item_type")
var dictItemType: Int = 0,
@ColumnInfo(name = "dic_item_name")
var dictItemName: String = "",
@ColumnInfo(name = "dic_item_detail")
var dictItemDetail: String = ""
)
从上面代码中可以看到,我新建了三个数据类,实际根据你的需求来,而且第三个dictionaryData是之前的,之后可能会改,暂时先放在这,反正目前也没用到。
怎么使用相信你看看上面的代码就能了解个大概了,PrimaryKey是必须要有的,这是SQL数据表的基础知识这里就不说了,其他的话就是写一个ColumnInfo,数据表多一列,没啥难的地方。
3、创建数据库操作接口Dao
在database文件夹内新建一个CreateBookDao的接口文件,注意在创建时选择interface类型
之后写入数据库操作函数
@Dao
interface CreateBookDao {
@Insert
suspend fun insertBook(book: Book)
@Update
suspend fun updateBook(book: Book)
@Insert
suspend fun insertChapter(chapter: Chapter)
//获取id最大的书
@Query("SELECT * FROM fictionData ORDER BY fiction_id DESC LIMIT 1")
suspend fun getLastBookId(): Book?
//获取一本书的id号,用于后续删除
@Query("SELECT * FROM fictionData WHERE fiction_id = :idF")
suspend fun getBookOfId(idF: Int): Book?
}
可以看到操作函数包含了增删改查的基本内容,只是示例这些函数怎么写,后续会不会用到就再说了。
4、创建数据库
在上述两步创建完成后,就可以创建本软件的数据库了,在database文件夹中新建AppDatabase文件,并写入如下代码:
@Database(
entities = [Book::class, Chapter::class, Dictionary::class],
version = 1,
exportSchema = false
)
abstract class AppDatabase : RoomDatabase() {
abstract fun createBookDao(): CreateBookDao
companion object {
@Volatile
private var instance: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
return instance ?: synchronized(this) {
Room.databaseBuilder(
context,
AppDatabase::class.java,
"fiction_database"
)
.build().also { instance = it }
}
}
}
}
这段代码中,函数名上边的Database括号里面的,一个是刚刚写的数据类,一个是数据库版本,最后一个好像是导出什么数据库操作之类的,false就对了。
其次,定义好的接口要用的时候都是这么声明。
abstract fun createBookDao(): CreateBookDao
然后下面的数据库这段代码直接复制就行,我也不知道,但是这样写是最好的,你看到的其他简化方法都会影响数据库的稳定性,这里面能改的只有getInstance的这个函数名。
好的到这里数据库整套就创建完成了,当然它不能运行,因为数据库只能在后台线程运行,如果你在主线程运行的话,当你操作大量数据时,会导致UI无响应,主线程只负责UI的刷新,所以其他操作都要移动到子线程去。
之后我们要做的是实现Room的功能,那么这里就要用到另外一个东西:ViewModel。
说实话,这个东西我也没搞明白,所幸根据官方给的例子跑通了整个代码,但是你让我解释其中为什么要这么做,我应该是解释不了,毕竟我只想实现我的软件功能,并不想系统的把所有知识掌握。