Android实现永久存储数据的三种方式

Android实现永久存储数据的三种方式(Kotlin实现)

1.通过文件的方式

1.1 适用范围

一些简单的文本数据

1.2 简单实例

作用:实现文本框可以在重新启动之后仍然保留上一次推出时候的数据

1.2.1 布局代码

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="请输入"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

其中较难懂的参数为ems 表示为控件的字符串长度,超出部分将不再进行显示

1.2.2 Activity代码

package com.example.csdnsqlite

import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.android.synthetic.main.activity_main.*
import java.io.*
import java.lang.StringBuilder
import kotlin.math.log

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val text=load()
        editText.setText(text)
        editText.setSelection(text.length)
    }

    override fun onDestroy() {
        //在每次活动结束时候 将文本进行存储
        super.onDestroy()
        val text=editText.text.toString()
        save(text)
    }

    private fun save(Text:String){
        try {
            val output=openFileOutput("data", Context.MODE_PRIVATE)
            val writer=BufferedWriter(OutputStreamWriter(output))
//            writer.use { // use当写入完成之后,可以自动关闭流,不用再手动关闭
//                it.write(Text)
//            }
            writer.write(Text) //这种方法需要自己手动关闭 注意关闭的顺序与开启的顺序刚好相反
            writer.close()
            output.close()
        }catch (e:IOException){
            e.printStackTrace()
        }
    }

    private fun load():String{
        val text=StringBuilder()
        try {
            val input=openFileInput("data")
            val reader=BufferedReader(InputStreamReader(input))
//            reader.use { //无需手动关闭 
//                reader.forEachLine {
//                    text.append(it)
//                }
//            }
            reader.forEachLine { //与上面相同 这种方式需要手动进行关闭
                text.append(it)
            }
            reader.close()
            input.close()
        }catch (e:IOException){
            e.printStackTrace()
        }
        return text.toString()
    }
}

首先获得文件的输出流,通过Context中的openFileOutput函数
openFileOutput接受两个参数
第一个:文件名称
也就是你存储的那个文件叫什么名字
第二个:关于写入方式的参数,有两个
MODE_PRIVATE表示若出现同名文件,则会进行覆盖;MODE_APPEND表示若出现同名文件,则继续往里面添加
之后根据获取的FileoutputStream对象,通过java流的方式写入文件
获取一个BufferedWriter对象,可以通过这个对象对文件进行写入
方法:BufferedWriter(OutputStreamWriter(刚获得的FileoutputStream))

要获得文件的输入流,通过刚刚类似的openFileInput
openFileOutput接受一个参数:
文件名称,就是你刚刚存储的那个文件的名称,至于为什么不需要路径,那是因为android这些文件都有固定的路径,只需要文件名称就可以唯一确定文件
根据获取的FileinputStream对象,可以对文件内容进行读取
方法:BufferedReader(InputStreamReader(刚获得的FileinputStream))

运行时:
在这里插入图片描述

2.通过sharedpreferences来进行存储

2.1适用范围

这种方式是通过键值对的方式来进行存储,常见的使用情况,有存储用户的偏好设置等情况

2.2 简单实例

一个可输入文本框,下面两个按钮,一个用来存储数据,一个用来读取数据

2.2.1 布局代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:ems="10"
        android:hint="请输入"
        android:inputType="textPersonName"
        android:textSize="24sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/buttonSave"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="save"
        app:layout_constraintEnd_toStartOf="@+id/buttonLoad"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/buttonLoad" />

    <Button
        android:id="@+id/buttonLoad"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="Load"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/buttonSave"
        app:layout_constraintTop_toBottomOf="@+id/editText" />
</androidx.constraintlayout.widget.ConstraintLayout>

该布局主要是通过constraintlayout来完成的,其实大部分在图形化界面中完成的。。。。这种代码说实话有点难看懂,总之有一个文本输入框和两个按钮就可了。

2.2.2 Activity代码
package com.example.csdnsharedpreferences

import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        buttonSave.setOnClickListener {
            val text=editText.text.toString()
            val editor=getSharedPreferences("data",0).edit()
            editor.putString("text",text)
            editor.apply()
        }
        buttonLoad.setOnClickListener {
            val prefs=getSharedPreferences("data", Context.MODE_PRIVATE)
            val text=prefs.getString("text","")
            editText.setText(text)
            if (text != null) {
                editText.setSelection(text.length)
            }
        }
    }
}

写入:

  1. 通过getSharedPreferences的edit获取一个SharedPreferences.Editor!对象
    getSharedPreferences接受两个参数:
    第一个: 文件名称
    也就是你存储的那个文件叫什么,这种方式是通过xml的文件格式来进行存储的
    第二个:操作模式
    目前只有Context.MODE_PRIVATE也就是0,其余的几种模式在Android发展过程中都被废弃了。。。

  2. 之后通过putString,putInt等一系列put方法往里面添加数据
    添加格式为 key:value格式 ,两个参数一个为键,一个为值

  3. 添加完之后,一定要进行apply进行保存更改

读取:

  1. 通过getSharedPreferences获取一个SharedPreferences对象,参数与写入时候相同

  2. 根据获得的对象 调用getString,getInt等函数,获取所需要的数据
    参数一般为两个:
    第一个:键 第二个:没有找见的时候的默认值

2.2.3 运行效果

在这里插入图片描述

3.通过SQLite数据库来进行存储

3.1使用情况

在面对一些复杂的数据的时候,前面两种方式就显得比较老土了,肯定无法胜任,这就需要数据库出马了,android本身是内置数据库的,短小而精悍的SQLite数据库成为了不二之选。

3.2简单示例

3.2.1讲解

android为了方便进行数据库的管理,提供了一个名为SQLiteOpenHelper的类,来帮助我们,不过不能直接用,这个类是个抽象类,当我们想使用的时候,必须用自己的类去继承这个类,主要实现两个抽象的方法:onCreate和onUpdate,看看名字也能猜出来,一个是创建的时候进行调用,另一个是当数据库升级的时候进行调用。

SQLiteOpenHelper可以通过getReadableDatabase和getWritableDatabase来打开的数据库,不存在则创建,区别在于前一种方法当数据库无法写入的时候,例如存储空间满了的时候,会以只读的方式打开,而后者则会报错。

就不写布局文件了,就是一些简单的按钮,直接看Activity等文件吧

3.2.2 创建数据库

创建一个数据库,用于记录学生的信息,简单起见,就姓名,年龄,性别,学号吧。
如果学过SQL,创建表的话,应该这么写

CREATE TABLE Student(
id integer primary key autoincrement,
name text ,
age integer,
sex boolean,
stuNo text)

新建一个文件StudentDatabaseHelper来完成创建表的操作

package com.example.csdndatabase

import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.widget.Toast

class StudentDatabaseHelper(val context: Context,name :String,version :Int):
    SQLiteOpenHelper(context,name,null,version) {
    private val createTable= "CREATE TABLE Student(\n" +
            "id integer primary key autoincrement,\n" +
            "name text ,\n" +
            "age integer,\n" +
            "sex boolean,\n" +
            "stuNo text)"
    
    override fun onCreate(db: SQLiteDatabase?) {
        db?.execSQL(createTable)
        Toast.makeText(context,"create",Toast.LENGTH_SHORT).show()
    }

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

SQLiteOpenHelper接受四个参数
1.上下文对象,为了保证可以对数据库进行操作
2.数据库的名称
3.cursor一般情况下为null,查询时候会返回这么一个对象,里面有我们所查询到的信息
4.数据库的版本,为整型

MainActivity代码

package com.example.csdndatabase

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val dbHelper=StudentDatabaseHelper(this,"StuData.db",1)
        buttonCreateDatabase.setOnClickListener {
            dbHelper.writableDatabase //实际上调用了getWritableDatabase
        }
    }
}

再调用getWritableDatabase,因为没有创建数据库,会在调用时,自动创建数据库。

运行时:
在这里插入图片描述
可以看到,第一次点击的时候创建了数据库,之后再点击,没有响应,那是因为只有第一次才会调用oncreate函数,之后发现已经创建成功了,就不会再进行调用了。

怎么确定创建了数据库呢?
点击右下角的Device Explorer(根据版本的不同,你的可能不在那里,但是稍微找找,,应该很好找见)
之后按以下步骤就可以找见数据库了,在com.example.你的项目名称处进行寻找。里面有一个你创建的db文件,另一个则是生成的日志文件。
在这里插入图片描述
想看一下数据库里面的内容?
需下载DB Browser
选择File–Settings–Plugins 输入DB Browser 就可以下载安装了
找不见这个工具的话,ctrl+shift+A 输入DB Browser进行搜索

笔者用着这小程序有点问题 又下载了个sqlitebrowser
认识中国字 稍微看看 应该就会用了
打开后的内容如下:
在这里插入图片描述
数据库的基本操作是增删查改~ 接下来 对表进行插入
插入操作:
更改一下布局,在下面再增加一个按钮,用于添加数据
对MainActivity进行更改,在oncreate中添加如下代码:

 buttonAddData.setOnClickListener {
            val db=dbHelper.writableDatabase
            val values=ContentValues().apply {
                put("name","小明")
                put("age",18)
                put("sex",true)
                put("stuNo","123456")
            }
            db.insert("Student",null,values) //插入数据
        }

首先获取数据库对象,之后创建一个值,不用传入id,因为id会自动创建
最后进行插入
查看数据库内容,可以看出添加了几条数据:
在这里插入图片描述

更新操作:
继续增加按钮
MainActivity增加的代码如下:

        buttonUpdate.setOnClickListener {
            val db=dbHelper.writableDatabase
            val values=ContentValues()
            values.put("age",22)
            db.update("Student",values,"name=?", arrayOf("小明"))
        }

该代码将名字等于小明的年龄都改为了22
较难理解的是update的参数,共有四个:
第一个:
要进行改的表名
第二个:
你自己创建的ContentValues,其中包含要更改的信息
第三和第四个:
共同构成筛选条件,确定哪些行需要进行更改
更改后的数据如下:
在这里插入图片描述
删除操作
例如需要删除id=3的那行
先在布局中继续添加按钮
在MainActivity中添加代码:

        buttonDelete.setOnClickListener {
            val  db=dbHelper.writableDatabase
            db.delete("Student","id==?", arrayOf("3"))
        }

delete 第一个参数为表名,后两个决定删除的条件
删除数据后的结果如下:
在这里插入图片描述
查找操作:
查找操作较为复杂,通过query函数进行实现,其中包括七个参数

参数对应的SQL语句
tablefrom table_name
columnsselect column1,column2
selectionwhere column=value
selectionArgs就是上面的value
groupBygroup by column
havinghaving column=value
orderByorder by column1,column2

举一个较为简单的例子,查询所有数据,查询数据的时候,要将查询到的数据放在一个cursor中,之后进行读取。
现在界面中再增加一个按钮,MainActivity增加如下的代码:

        buttonSelect.setOnClickListener {
            val db=dbHelper.writableDatabase
            val cursor=db.query("Student",null,null,
                null,null,null,null)
            if (cursor.moveToFirst()){
                do {
                    val name=cursor.getString(cursor.getColumnIndex("name"))
                    val age=cursor.getInt(cursor.getColumnIndex("age"))
                    val StuNo=cursor.getString(cursor.getColumnIndex("stuNo"))
                    Log.d("MainActivity","$name is $age years old ,StuNo is $StuNo")
                }while (cursor.moveToNext())
            }
        }

一共有三条数据,可以看到打印的结果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值