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

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

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

现在写到题库部分。

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

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

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

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
    }
}

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

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

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

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

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
        }

    }


}

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

   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()
                }
            }


        }

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

调用,db.query(xxx)...

  val temSql = mySql(activity,"glx",1)
      
    xxx
   val db = temSql.writableDatabase

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

这里用到的kt文件流,思路来自:。