SharedPreferences
SharedPreferences 存储的是xml文件,文件中是键值对的方式
SharedPreferences 是轻量级存储类,存储在 "data/data/当前应用包名/shared_prefs/文件名.xml"
SharedPreferences 是线程安全的,因为加了 synchronized
apply 同步写回内存,然后把异步写回磁盘的任务放到一个单线程的队列中等待调度
commit 和apply一样的写回操作,只是要等待异步任务返回,才返回
apply/commit 是把全部数据进行一次写操作,所以单个文件不应该过大,如果实在需要很多内容,可以分为不同的文件
1.获取 SharedPreferences
getSharedPreferences("data_activity",Context.MODE_PRIVATE) // activity中使用
applicationContext.getSharedPreferences("data_application",Context.MODE_PRIVATE)
PreferenceManager.getDefaultSharedPreferences(context) // 过期了,不建议使用
SharedPreferences getSharedPreferences(String name, int mode)
name: 文件的名字
mode:使用 MODE_PRIVATE 或者 MODE_APPEND 另外两个高版本不能使用
Context.MODE_PRIVATE: 指定该SharedPreferences数据只能被本应用程序读、写;
Context.MODE_WORLD_READABLE: 指定该SharedPreferences数据能被其他应用程序读,但不能写;
Context.MODE_WORLD_WRITEABLE: 指定该SharedPreferences数据能被其他应用程序读;
Context.MODE_APPEND:该模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件;
2.SharedPreferences基础使用
val hashSet = HashSet<String>()
hashSet.add("ss")
hashSet.add("aa")
hashSet.add("dd")
// 1.获取/创建 SharedPreferences 对象
val sp = getSharedPreferences("data_activity", Context.MODE_PRIVATE)
// 2.获取/创建 Editor 对象
val editor: Editor = sp.edit()
btn_put.setOnClickListener {
// 3.放入内容
editor.putString("name", "lucky")
editor.putInt("age", 22)
editor.putFloat("weight", 60f)
editor.putBoolean("isBig", false)
editor.putLong("nn", 23L)
editor.putStringSet("setkey", hashSet)
// 4.提交 commit,推荐apply commit同步,apply异步,防止阻塞UI线程
editor.apply()
}
下方 xml 文件内容
btn_get.setOnClickListener {
// 5. 获取值
val name = sp.getString("name", "")
Log.d("sp_sp", name)
}
btn_remove.setOnClickListener {
// 6. 移除指定key的 项
editor.remove("weight")
editor.apply()
}
btn_clear.setOnClickListener {
// 7. 清空数据
editor.clear()
editor.apply()
}
//注册 sp数据变化监听 增加,删除,更新 会回调,清空不会回调
sp.registerOnSharedPreferenceChangeListener(listener)
val listener = SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
Log.d("sp_sp", "sharedPreferences:" + sharedPreferences.all+" key:"+key)
}
// 反注册
sp.unregisterOnSharedPreferenceChangeListener(listener)
添加内容后:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<long name="nn" value="23" />
<string name="name">lucky</string>
<float name="weight" value="60.0" />
<boolean name="isBig" value="false" />
<int name="age" value="22" />
<set name="setkey">
<string>ss</string>
<string>aa</string>
<string>dd</string>
</set>
</map>
移除内容后:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<long name="nn" value="23" />
<string name="name">lucky</string>
<boolean name="isBig" value="false" />
<int name="age" value="22" />
<set name="setkey">
<string>ss</string>
<string>aa</string>
<string>dd</string>
</set>
</map>
清空内容后:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map />
3.SharedPreferences kotlin 进阶使用
@Suppress("UNCHECKED_CAST")
class SpHandler<T>(private val key: String = "", private val defaultValue: T) :
ReadWriteProperty<Any, T> {
init {
Log.d("sp_sp", "初始化")
}
val sp: SharedPreferences by lazy {
MyAppLication.context.getSharedPreferences("sp_sp", Context.MODE_PRIVATE)
}
fun clear(){
sp.edit().apply {
clear()
apply()
}
}
fun remove(key: String){
sp.edit().apply{
remove(key)
apply()
}
}
override fun getValue(thisRef: Any, property: KProperty<*>): T {
val keyName = if (key.isEmpty()) property.name else key
return with(sp) {
when (defaultValue) {
is Long -> getLong(keyName, defaultValue) as T
is String -> getString(keyName, defaultValue) as T
is Float -> getFloat(keyName, defaultValue) as T
is Int -> getInt(keyName, defaultValue) as T
is Boolean -> getBoolean(keyName, defaultValue) as T
else -> throw IllegalArgumentException("没有对应的类型,请检查一下")
}
}
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
val keyName = if (key.isEmpty()) property.name else key
with(sp.edit()) {
when (value) {
is Long -> putLong(keyName, value)
is String -> putString(keyName, value)
is Float -> putFloat(keyName, value)
is Int -> putInt(keyName, value)
is Boolean -> putBoolean(keyName, value)
else -> throw IllegalArgumentException("没有对应的类型,请检查一下")
}
apply()
}
}
}
class SharedPreferencesActivity : AppCompatActivity() {
lateinit var sp: SharedPreferences
var name by SpHandler(defaultValue = "")
var age by SpHandler(defaultValue = 10)
override fun onCreate(savedInstanceState: Bundle?) {
btn_good_add1.setOnClickListener {
name = "hello" // 等效于 putString(key,value)
// getString 时,直接使用 name 就表示获取的值
}
btn_good_add2.setOnClickListener {
age = 111
}
btn_good_clear.setOnClickListener {
SpHandler(defaultValue = "").clear()
}
}
}
内部存储
内部存储是存储在Android文件系统的特殊位置 /data/user/0/应用的包名/files
/data/user/0/应用的包名/files 是通过api获取的地址,其实际地址在文件目录中是 /data/data/应用的包名/files
内部存储不需要权限
1.查看可用空间
通过调用 getFreeSpace() 或 getTotalSpace() 确定是否有足够的可用空间,而不引发 IOException
在 activity中 可 filesDir.freeSpace 获取
2.写入文件
val file = File(filesDir,"fileDemo.txt") // 用于指定 创建文件的地址和名字
// 1. 调用 openFileOutput() 以获取目录中的文件的 FileOutputStream
openFileOutput(file.name, Context.MODE_PRIVATE).use {
// 2. 写入内容
it.write("写入内容".toByteArray())
}
3.读取文件内容
// 1. 通过 openFileInput 获取 FileInputStream
// 2. 通过 readBytes 读取数据
val readBytes = openFileInput("fileDemo.txt").readBytes()
// 3. 将bytes转为String
val content = String(readBytes)
Log.d("internal_s", content)
4. 删除文件
val file = File(filesDir, "fileDemo.txt")
file.delete()
// deleteFile("fileDemo.txt")
5. 文件追加内容
i++
val file = File(filesDir,"fileDemo2.txt") // 用于指定 创建文件的地址和名字
// 1. 调用 openFileOutput() 以获取目录中的文件的 FileOutputStream
openFileOutput(file.name, Context.MODE_APPEND).use {
// 2. 写入内容
it.write("写入内容 ${i} ".toByteArray())
}
只需要 mode 改为 Context.MODE_APPEND 就是追加模式
6. 文件夹中文件数
val listFiles = File(filesDir.absolutePath).listFiles()
Log.d("internal_s", "listFiles:${listFiles.size}")
7. 内部存储读写另外一种通用方法
写操作
// 创建 文件 目录
val parentFile = File(filesDir.path)
parentFile.mkdirs()
// 创建文件
val file = File(parentFile,"/music.txt")
if (!file.exists()) {
file.createNewFile()
}
FileWriter(file).use {
it.write("wwwwwewfxfsd\nsdfdsfsdfsdf")
// it.append("xsadas")
}
读操作
val exists = file.exists()
val isFile = file.isFile
if (exists && isFile) {
}
val charArray = CharArray(1024)
val stringBuffer = StringBuffer()
FileReader(file).use {
while (true) {
val len = it.read(charArray)
if (len < 0) {
break
}
stringBuffer.append(String(charArray, 0, len))
}
Log.d("SD_CARD", stringBuffer.toString())
}
外部存储
外部存储主要是用于 与其他应用共享文件,但是在7.0后,需要使用contentProvider
外部存储通常就是我们认为的 sdcard目录下的文件存储
外部存储 需要申请 权限 READ_EXTERNAL_STORAGE 或者 WRITE_EXTERNAL_STORAGE
1.申请权限
AndroidManifest.xml中 添加如下权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Android 6.0后 需要动态申请权限
if (checkSelfPermission != PackageManager.PERMISSION_GRANTED) {
val permissions = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
requestPermissions(permissions, 99)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 99) {
if (grantResults.isNotEmpty()
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
) {
Toast.makeText(this, "已经申请了读写权限", Toast.LENGTH_LONG).show()
}
}
}
2.使用公有外部存储
app卸载后,不会被清理
路径:/storage/emulated/0/自己命名的文件目录/自己命名的文件名字
写操作
// 1.判断 SDcard状态
val state = Environment.getExternalStorageState()
if (state == Environment.MEDIA_MOUNTED){
}
// 2. 获取/创建 外部文件夹 虽然这个方法过期了,但还是可以用
val publicDir = Environment.getExternalStoragePublicDirectory("myfie")
// 3. 创建 文件目录
val parentFile = File(publicDir.path)
parentFile.mkdirs()
// 4. 创建文件
val file = File(parentFile,"/222.txt")
if (!file.exists()) {
file.createNewFile()
}
// 5. 写内容到文件
FileWriter(file).use {
it.write("wwwwwewfxfsd\nsdfdsfsdfsdf")
// it.append("xsadas")
}
读操作
// 1. 判断文件是否存在,是否是文件类型
val exists = file.exists()
val isFile = file.isFile
if (exists && isFile) {
}
// 2 .创建接收的 容器
val charArray = CharArray(1024) // 根据文件中的数据选择不同的容器 这里文件中是String
val stringBuffer = StringBuffer() // 根据文件中的数据选择不同的容器 这里文件中是String
// 3 .读文件
FileReader(file).use {
while (true) {
val len = it.read(charArray)
if (len < 0) {
break
}
stringBuffer.append(String(charArray, 0, len))
}
Log.d("SD_CARD", stringBuffer.toString())
3.使用私有外部存储
app卸载,会跟随被清理
路径:/storage/emulated/0/Android/data/包名/files/Music // Music: Environment.DIRECTORY_MUSIC
// 获取/创建 外部文件夹 (私有文件夹)Environment.类型
val music = getExternalFilesDir(Environment.DIRECTORY_MUSIC)
// 其他和公有外部文件存储一样
注意:
不管内部存储还是外部存储都是文件存储,所以,在文件上的操作是相通的
未完待续......
网友评论