Kotlin安卓开发:导入外部数据库

  1. 涉及到内部数据库的创建使用。
  2. 外部数据库的导入。
  3. kotlin的文件读写。

最近在写一个学习资料类的应用。

现在写到题库部分。

思路是:事先准备好外部的数据库(就是题库了),然后,程序第一次运行时候,首先创建内部数据库,然后将外部数据库复制到内置,外置数据库文件在assets里面。内置的在/data/data/com.包名/databases/数据库名

首先写一个SQL类,用来创建程序内置数据库,这个数据库结构和外部要一致!初始化是空的。

mySql类:用来初始化内置类,程序运行第一次会初始化一个数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class mySql(context: Context,name:String,version:Int ):SQLiteOpenHelper(context,name,null,version) {

val Create_ = "Create table sj(id integer primary key autoincrement,name varchar);"
//SQL语句与平时用的SQL一致,创建试卷表
val mContext = context
var sjs = arrayListOf<Map<String, Any>>()//存放数据,试卷表的数据
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
//这是以后用来升级数据库用的,暂时不用
}

override fun onCreate(db: SQLiteDatabase?) {
//继承的是help数据库类,这个方法会在新建对象时候调用。
try {
db!!.execSQL(Create_)
//强制执行SQL
Log.d("dbInit","")
//这个方法,会检测数据库是否存在,存在将不会再重新创建!
Toast.makeText(mContext, "初始化数据库", Toast.LENGTH_SHORT).show()
} catch (e: NullPointerException) {
println(e)
}
}

//这里是查询
fun wen_query( db: SQLiteDatabase, hand: Handler): Boolean {
xxx
return false
}
}

null

在main活动里:初始化这个数据库对象(不用担心以后会被覆盖)

1
2
 val temSql = mySql(this@MainActivity,"glx",1)//初始化数据库
//参数:context,数据库名,版本(随意)

null

然后,我们就要把外置的数据库复制过来了。

看看ImportDB类,用来复制我们外面的数据库文件:这里一定注意,会有很多问题出现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class ImportDB internal constructor(private val context: Context) {
private val BUFFER_SIZE =10000
//一会下面会按照字节读取
//伴生对象,在主活动里,检测是否存在数据库文件会用到
companion object {
val DB_NAME = "glx" //保存的数据库文件名
val PACKAGE_NAME = "com.simplewen.win0"//工程包名
val DB_PATH = ("/data${Environment.getDataDirectory().absolutePath}/$PACKAGE_NAME/databases") //在手机里存放数据库的位置
}
fun copyDatabase():Boolean{
val dbfile = "$DB_PATH/$DB_NAME"
Log.d("look",dbfile)
try {


//执行数据库导入
val db = this.context.resources.assets.open("glx") //欲导入的数据库
val fos = FileOutputStream(dbfile)
val buffer = ByteArray(BUFFER_SIZE)
var count = 0
//这里很多小伙伴一定看到过java版的,AS一键转kt,会出现一个问题!,
//就是:count=db.read出现在了while里面,这会报红,kt不支持在while语句出现赋值语句,要用匿名函数。
while ({ count = db.read(buffer);count}() > 0) {
fos.write(buffer, 0, count)
}
fos.close()//关闭输出流
db.close()//关闭输入流
return true
}catch (e: Throwable) {
Log.d("look",e.toString())
e.printStackTrace()
return false
}

}


}

null

我们看看主活动:这里思路,当数据库初始化以后,我们开始导入外部数据库,如果导入完成,设置flag为1,下次启动检测,防止重复导入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
val file = File(ImportDB.DB_PATH + "/glx")//调用伴生对象
Log.d("here",ImportDB.DB_PATH)
val share = getSharedPreferences("dbFlag", Activity.MODE_PRIVATE)

if (file.exists()){
//内部数据库存在,开始导入外部
Toast.makeText(this@MainActivity, "存在内部数据库", Toast.LENGTH_SHORT).show()
if(share.getString("dbFlag","0") == "1"){
Toast.makeText(this@MainActivity, "已经导入过数据库", Toast.LENGTH_SHORT).show()
}else{
val inDb = ImportDB(this@MainActivity)
if(inDb.copyDatabase()){
Toast.makeText(this@MainActivity, "复制完成", Toast.LENGTH_SHORT).show()
val shareP = getSharedPreferences("dbFlag", Activity.MODE_PRIVATE)
val edit = shareP.edit()
edit.putString("dbFlag","1")//导入完成,设置标志
edit.apply()
}else{
Toast.makeText(this@MainActivity, "复制失败", Toast.LENGTH_SHORT).show()
}
}


}

null

最后,看看具体使用:在另一个FG里面使用:这个时候,由于数据库已经存在,再初始化一个对象,将会默认使用新的数据库。

调用,db.query(xxx)…

1
2
3
4
val temSql = mySql(activity,"glx",1)

xxx
val db = temSql.writableDatabase

null

好了,这个问题,网上太多java的资料了,kt很少,这里和kt小伙伴分享一下,小总结。

这里用到的kt文件流,思路来自:https://www.cnblogs.com/dwb91/p/9049537.html