Android Studio 如何从脚本或数据库中插入数据到Jetpack Compose Room数据库?

sczxawaw  于 2023-10-23  发布在  Android
关注(0)|答案(1)|浏览(138)

我正在创建一个肯定句应用程序。这个应用程序将显示用户积极的句子,当他们滚动页面向上或向下,它会显示另一个肯定的消息等。有时候,他们会发出通知。但是为了向人们展示这些句子,我需要从DB室之类的地方获取它们。我解决这个问题的方法是直接将所有数据插入到用户本地的Room DB中,然后在没有互联网连接的情况下获取所有的句子。但要实现这一点,我需要知道是否可以插入整个脚本文件到数据库。例如,我将有一个脚本文件与100个查询,当我运行它将直接插入100个数据到我的本地数据库。我如何才能做到这一点?谢谢.

3mpgtkmj

3mpgtkmj1#

但要实现这一点,我需要知道是否可以插入整个脚本文件到数据库。
利用预填充的数据库并将其作为资产提供可能会更简单。然而,是的,它当然可以使用脚本文件(SQL INSERT s)。

预填充数据库的简单性

SQLite数据库是一个可以复制的文件(通常使用Room的databaseBuilder的createFromAsset方法从assets文件夹中复制)。数据只是读然后写。
为了处理脚本,数据必须被读取、处理和插入,就像你提到的脚本一样,在一个循环中。所以你必须编写一个循环来进行处理。您还必须在正确的时间执行此操作(很可能是通过覆盖CallBackonCreate方法)。所以需要更多的代码。
然而,Room在模式方面非常不灵活。简而言之,它必须是预期的房间(或调整,这将是另一个编码复杂性)。
1.根据Room的预期模式创建数据库的简单方法是
1.编写@Entity注解类(表),然后
1.用@Database注解的entities参数编码一个@Database注解的抽象类,包括所有@Entity注解的类,然后
1.成功编译项目,然后
1.找到与@Database注解类同名但后缀为_Impl的类,然后
1.找到createAllTables方法,然后
1.复制SQL以创建表(以及其他组件,如索引)。

Demo

下面演示了两个工作示例,为两个数据库加载了大约10000行数据:

  1. senetenc1.db(预填充)
  2. db2 .db(通过“脚本”填充,即执行SQL语句)
    两者的模式是完全相同的,并且基于单个@Entity注解类[Sentence]:
@Entity
data class Sentence(
    @PrimaryKey
    val sentenceId: Long?=null,
    val sentence: String,
    val usage: Int
)

然后创建了两个@Database注解类(如下),编译后的项目允许从生成的java中复制用于创建表的SQL:

在这个阶段,可以很容易地生成两个数据源,数据库和脚本文件(所有10000行的id都是相同的数据栏)。
在SQLite工具中,使用了以下内容:

DROP TABLE IF EXISTS sentence;
CREATE TABLE IF NOT EXISTS `Sentence` (`sentenceId` INTEGER, `sentence` TEXT NOT NULL, `usage` INTEGER NOT NULL, PRIMARY KEY(`sentenceId`));
WITH
    cte_counter(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM cte_counter LIMIT 10000)
INSERT INTO sentence (sentence,usage) SELECT 'The quick brown fox jumped over the lazy dogs.',0 FROM cte_counter
;
  • 注意,CREATE语句是从生成的java中复制的(如上所述)

在文本编辑器中,单个插入语句重复了99999次

INSERT INTO `Sentence` (`sentence`,'usage') VALUES ('The quick brown fox jumped over the lazy dogs.',0);

关闭数据库,然后将其复制到assets文件夹中(创建后)。同样,文本文件也被复制到assets文件夹中:

Sentence 1 @Database annotated class-处理预填充数据库(asset pixelce1.db):-

@Database(entities = [Sentence::class], exportSchema = false, version = 1)
abstract class SentenceDatabase1: RoomDatabase() {
    abstract fun getSentenceDao(): SentenceDao

    companion object {
        val TAG = "DBINFO_1"
        private var instance: SentenceDatabase1?=null
        fun getInstance(context: Context): SentenceDatabase1 {
            if (instance==null) {
                Log.d(SentenceDatabase1.TAG,"Starting Database Build")
                instance=Room.databaseBuilder(context,SentenceDatabase1::class.java,"sentence1.db")
                    .allowMainThreadQueries()
                    .createFromAsset("sentence1.db")
                    .build()
            }
            Log.d(SentenceDatabase1.TAG,"Finished Database Build")
            return instance as SentenceDatabase1
        }
    }
}
  • 可以看出,createFromAsset是一段简单的单行代码
    Sentence 2 @Database annotated class-要处理通过Scripce2.txt文件的“Scripted”加载,请执行以下操作:-
@Database(entities = [Sentence::class], exportSchema = false, version = 1 )
abstract class SentenceDatabase2: RoomDatabase() {
    abstract fun getSentenceDao(): SentenceDao

    companion object {
        val TAG = "DBINFO_2"
        @SuppressLint("StaticFieldLeak")
        private var instance: SentenceDatabase2? = null
        @SuppressLint("StaticFieldLeak")
        lateinit var passedContext: Context
        fun getInstance(context: Context): SentenceDatabase2 {
            if (instance==null) {
                passedContext = context
                Log.d(TAG,"Starting Database Build")
                instance=Room.databaseBuilder(context,SentenceDatabase2::class.java,"sentence2.db")
                    .allowMainThreadQueries()
                    .addCallback(cb)
                    .build()
            }
            Log.d(TAG,"Finished Database Build")
            return instance as SentenceDatabase2
        }

        val cb = object: RoomDatabase.Callback() {
            @Override
            override fun onCreate(db: SupportSQLiteDatabase) {
                super.onCreate(db)
                val br = passedContext.assets.open("sentence2.txt").bufferedReader()
                br.forEachLine {
                    db.execSQL(it)
                }
            }
        }
    }
}
  • 引入了一个回调,它覆盖了onCreate函数(在创建数据库时调用的函数,即数据库的生存期为ONCE)。
  • 该函数获取资产,并对每行使用作为传递给execSQL函数的字符串,执行10000个重复测试。
  • 请注意,为了简洁和方便起见,演示使用了主线程。此外,上下文是以不应该的方式获得的,因为它会泄漏内存。

最后是代码:

class MainActivity : AppCompatActivity() {
    lateinit var dbDatabase1: SentenceDatabase1
    lateinit var dbDatabase2: SentenceDatabase2

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        dbDatabase1 = SentenceDatabase1.getInstance(this)
        dbDatabase2 = SentenceDatabase2.getInstance(this)
        dbDatabase1.openHelper.writableDatabase
        dbDatabase2.openHelper.writableDatabase
    }
}
  • 请注意,同样为了简洁和方便,数据库是通过获取可写数据库(而不是利用@Dao注解接口中的函数)打开的。
  • 仅仅获取数据库的示例并不能打开数据库,因此什么也做不了。也就是说,直到尝试打开数据库时,数据库才被实际访问和创建(如果它还不存在)等

使用App Inspection,则

  • Sentence 1数据库具有预期的10000行

  • Setence 2数据库也具有预期的10000行

相关问题