【大树云微课堂】- Android 中数据存储的介绍和使用

Android 系统的存储空间有内外之分,内部的存储空间只能够被当前应用所访问,用户和其他应用都不行。外部存储则可以被用户通过自带的文件管理器可以查看。

内部存储

内部存储是 Android 系统内部的存储空间,由 Android 系统管理,普通用户无法查看该存储空间内的文件。 下面介绍常用的 3 种读写内部存储空间的方法

SharedPreference

SharedPreferences 是 Android 平台上一个轻量级的存储类,主要是保存一些常用的配置, 它提供了 Android 平台常规的 Long长整形、Int整形、String字符串型的保存。
它所保存的文件是以 xml 的格式存储在 /data/data//sharedprefs 目录下。使用方式如下

// test 为 xml 文件的名字,第二个参数为模式

val share = getSharedPreferences("test", Context.MODE_PRIVATE)

    share.edit()

        .putBoolean("testBoolean", true)

        .apply()


按照上述代码,将会生成 /data/data//sharedprefs/test.xml 文件,文件内容如下



可以看出,在代码中设定的 testBoolean 对应值 true 都被保存下来了。


SQLite

SQLite 为 Android 所提供的数据库工具,能够以数据库的形式存储数据,使用方法如下


class MySQLite(mContext:Context?,name:String?,factory: SQLiteDatabase.CursorFactory?,version:Int): SQLiteOpenHelper(mContext,name,factory, version) {

     override fun onCreate(db: SQLiteDatabase?) {

    }

     override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {

    }

}


首先得继承 SQLiteOpenHelper 这个类,继承后需要实现 onCreate 和 onUpgrade 方法。在使用时,直接创建该类即可。


val test = MySQLite(this,"test.db",null,1)


在第一次创建时,会进入 onCreate 方法,可以执行数据库表创建的工作,传入的文件名 "test.db" 也会被创建。

需要注意的是,在之后的使用时,传入的 version 如果和第一次使用的 version 不同,就会执行 onUpgrade 方法。在这个方法中,可以对数据表进行操作。

最终 db 类如下


class MySQLite(mContext:Context?,name:String?,factory: SQLiteDatabase.CursorFactory?,version:Int): SQLiteOpenHelper(mContext,name,factory, version) {

    val CREATE_TEST = ("create table test ( "

            + " id integer primary key autoincrement,"

            + " name text)")

    override fun onCreate(db: SQLiteDatabase?) {

        db?.execSQL(CREATE_TEST)

    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {

        db?.execSQL("drop table if exists test")

        onCreate(db)

    }

}


但此时,在手机的内部存储中,还是没有看到 test.db 的文件了,那是因为在实际使用前,都不会去执行 onCreate 的方法。


实际使用

先在 MySQLite 类中添加新增和查询数据的方法


fun search(){

    // 查询数据

    val queryData = writableDatabase.query("test",null,null,null,null,null,null,null)

    if(queryData.moveToFirst()){

        // 遍历数据

        do{

            val name = queryData.getString(queryData.getColumnIndex("name"))

            val id = queryData.getString(queryData.getColumnIndex("id"))

            println(name)

            println(id)

        }while(queryData.moveToNext())

    }

    queryData.close()

}

fun add(data: ContentValues){

    // 添加数据

    writableDatabase.insert("test",null,data)

}


在 MainActivity 中调用


fun test(){

val helper = MySQLite(this,"test.db",null,1)

        val data = ContentValues()

        data.put("name","Test")

        helper.add(data)

        helper.search()

}

在调用该方法后,就可以在手机的内部存储中看到 test.db 文件,并且此时控制台输出了查询的结果。





文件

Android 系统中提供了 openFileOutput 和 openFileInput 方法来读写内部存储空间的文件。

吸入的文件默认存储在内部存储空间的 /data/data//files 目录中,可以通过 Android Studio 来查看这些文件。

openFileOutput 方法是写入数据,接受的第一个参数时文件名,如果不存在则先新建一个。第二个参数则是写入模式,现在只接受 Context.MODE_PRIVATE 和 Context.MODE_APPEND。

前者表示每次写入都会覆盖当前内容,后者则是在当前基础上添加数据。使用如下:


val file = openFileOutput("a.txt", Context.MODE_PRIVATE)

file.write("123456".toByteArray())


在 Android Studio 中可以查看到该文件





openFileInput 则是读取文件,使用如下


val data = openFileInput("a.txt").bufferedReader().readLine()

println(data)

控制台输出为 123456

外部存储

考虑到普通用户无法查看到内部存储的文件的问题,提供了外部存储的方式来存放数据。

 

应用私有目录

应用私有目录是谷歌提供给 APP 在外部存储上的目录,其目录为 Android/data//。在访问该目录时, app 不需要申请读写存储的权限也可以直接创建文件。( 为应用的包名)

私有目录在应用被卸载时,也会被清理掉,所以不应该存放与应用无关的数据。例如用户所保存的图片,文件,否则会导致应用删除时,用户保存的数据也随之丢失。

所以对于这一类在 APP 卸载时仍要保留的数据,需要存放到应用公共目录。

常用的访问私有目录的 API 有两个

  1. getCacheDir()
  2. getExternalFilesDir(type:String)

第一个方法获取到的路径为 Android/data//cache,是存放缓存文件的路径。

第二个方法则是接收一个字符串,使用 Environment 中提供的字符串变量,指向对应的私有目录。例如


val path = getExternalFilesDir(Environment.MEDIA_SHARED)

println(path)


控制台会输出 /storage/emulated/0/Android/data//files/shared


在获取到路径后,可以创建新的文件,并对其进行读写。

 

fun file(){

    // 获取私有目录路径

    val path =  getExternalFilesDir(Environment.MEDIA_SHARED)

    // 要新增的文件

    val add = "/test.txt"

    // 创建 File 类

    val file = File(path?.path + add)

    // 判断是否是文件

    if (file.isFile){

        println(file.readText())

    }else{

        // 是否创建失败

        if (!file.createNewFile()) {

            println("创建文件:$file 失败")

        }else{

        // 创建成功则写入数据

            file.writeText("123456")

        }

    }

}


在第一次打开 APP 时,会执行 file 函数并且会创建 test.txt 文件,在创建成功后,会在该文件写入 123456 。

此时关闭 APP 再次打开,一样会执行 file 函数,但因为文件已经创建,所以会直接读取该文件。控制台输出为 123456。

在文件管理工具中也可以查看到新增的文件。





应用公共目录

相对于私有目录,公共目录需要申请读写存储的权限,并且该目录下的文件也可以被其它具有读写存储权限的 APP 访问。使用方法如下

读写权限

对于公共目录,要先进行权限申请。在 AndroidManifest.xml 文件中进行权限申请。

 

 

 

除此之外,由于读写存储权限是危险权限,在 Android 6.0 以上的系统中,需要动态的进行申请。

 

/**

 * 动态申请权限

 */

private fun requestPermission() {

    // 检查是否拥有,有就直接用,没有就申请

    if (permissionCheck == PackageManager.PERMISSION_DENIED) {

        ActivityCompat.requestPermissions(this, arrayOf(WRITE_EXTERNAL_STORAGE,READ_EXTERNAL_STORAGE), 1000)

    } else {

        // 已经有权限,无需申请

    }

}

/**

 * 权限申请结果

 */

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {

    when (requestCode) {

        1000 -> {

            // 判断申请结果

        }

    }

}

 

路径获取

如果的到用户的同意,就具有对外部存储进行读写的权限了。获取外部存储目录的方法有两个

    1. Environment.getExternalStorageDirectory()
    2. Environment.getExternalStoragePublicDirectory(type:String)

其中第一个方法不接受参数,直接指向外部存储的根目录 /storage/emulated/0/,第二个方法接受一个字符串,使用 Environment 中提供的字符串变量,指向对应的公共目录。例如

val path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)

println(path)


控制台会输出 /storage/emulated/0/Pictures ,指向的是公共目录 Picture。

在获取到目录后并且申请了权限,则新建文件,写入文件,读取文件的方法都和使用私有目录时一样。

使用注意

  1. 由于目录是外部存储,也就是说用户可以随意删除更改,所以在代码编写时,需要对目录进行空判定,避免在读写被用户删除的文件时报错。
  2. 假如 APP 具有读写存储的权限,为了更好的用户体验,应该避免随意在用户的外部存储上随意创建文件,导致目录混乱;应按照 Android 提供的 API 来获取规定好的公有目录文件夹进行数据存放。如无必要,可以不用申请读写存储的权限。







★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★博文作者未开放评论功能