数据存储全方案,详解持久化技术

任何一个应用程序,其实就是不停地与数据打交道,我们聊微信、看新闻所关心地都是里面地数据,没有数据地应用程序就变成一个空壳子,对用户来说没有任何实际用途。那么这些数据是从哪里来的呢?现在多数地数据基本都是由用户产生的,比如微信发朋友圈、评论,其实都是在产生数据。
数据可以分为瞬时数据和持久化数据。所谓瞬时数据是指哪些存储在内存中,有可能会因为程序关闭或其他原因导致内存被回收而丢失的数据。比如:在登录页面数据账号和密码。持久化数据就是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或计算机关机的情况下,这些数据仍然不会丢失。
可以简单地认为:保存在内存中的数据处于瞬时状态,而保存在存储设备中的数据处于持久状态。持久化技术提供了一种机制,可以让数据在瞬时状态和持久状态之间进行转换。

Android系统中主要提供了3中方式用于实现数据持久化功能:文件存储、SharedPreferences存储以及数据库存储。

文件存储

文件存储是Android中最基本的数据存储方式,**它不对存储的内容进行任何格式化处理,所有数据都是原封不动地保存到文件当中的,因而它比较适合存储一些简单的文本数据或二进制数据。**如果想要使用文件存储的方式来保存一些较为复杂的结构化数据,就需要定义一套自己的格式规范,方便之后将数据从文件中重新解析出来。

将数据存储到文件中

Context类中提供了一个openFileOutput方法,可以用于将数据存储到指定文件中。这个方法接收两个参数:第一个参数是文件名,在文件创建的时候使用,注意这里的文件名不能包含路径,因为所有的文件都默认存储到/data/data/<package name‘>/files/目录下;第二个参数是文件的操作模式,主要有MODE_PRIVATE和MODE_APPEND两种模式可选,默认是MODE_PRIVATE,表示当指定相同文件名的时候,所写入的内容将会覆盖原文件中的内容,而MODE_APPEND则表示如果该文件存在,就往文件里面追加内容,不存在就创建新文件。其实,文件的操作模式还有另外两种:MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE。这两种模式表示允许其他应用程序对我们程序中的文件进行读写操作,已在Android4.2版本被废弃。

package com.example.myapplication

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import java.io.BufferedOutputStream
import java.io.BufferedWriter
import java.io.IOException
import java.io.OutputStreamWriter

class MainActivity : AppCompatActivity() {

    lateinit var timeChangeReceiver: TimeChangeReceiver

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    override fun onDestroy() {
        super.onDestroy()
        save("要保存的内容")//这样就能保证在activity销毁之前一定能保存数据
    }
    
    private fun save(inputText:String){
        
        try {
            val output = openFileOutput("data",Context.MODE_PRIVATE)
            val writer = BufferedWriter(OutputStreamWriter(output))
            writer.use {//kotlin提供的扩展函数,保证在lambda表达式中的代码全部执行完之后自动将外层的流关闭
                it.write(inputText)
            }   
        }catch (e:IOException){
            e.printStackTrace()
        }
    }
}

从文件中读取数据

类似于将数据存储到文件中,Context类中还提供了一个openFileInput方法,用于从文件中读取数据。这个方法要比openFileOutput方法简单一些,它只接收一个参数,即要读取的文件名,然后系统会自动到/data/data/<package name‘>/files/目录下加载这个文件,并返回一个FileInputStream对象,得到这个对象之后,再通过流的方式将数据读取出来。

    private fun load():String{
        val content = StringBuilder()
        
        try {
            val input = openFileInput("data")
            val reader = BufferedReader(InputStreamReader(input))
            reader.use {
                reader.forEachLine {
                    content.append(it)
                }
            }   
        }catch (e:IOException){
            e.printStackTrace()
        }
        return content.toString()
    }

SharedPreferences存储

不同于文件的存储方式,SharedPreferences是使用键值对的方式来存储数据的。也就是说,当保存一条数据的时候,需要给这条数据提供一个对应的键,这样在读取数据的时候就可以通过这个键把相应的值取出来。而且SharedPreferences还支持多种不同的数据类型存储,如果存储的数据类型是整型,那么读取出来的数据也是整型的;如果存储的数据是一个字符串,那么读取出来的数据仍然是字符串。

  • SharedPreferences文件是使用xml格式来对数据进行管理的

将数据存储到SharedPreferences中

想要使用SharedPreferences存储数据,首先要获取SharedPreferences对象。Android中主要提供了以下两种方法用于得到SharedPreferences对象。

  1. Context类中的getSharedPreferences()方法
    此方法接收两个参数:第一个用于指定SharedPreferences文件的名称,如果指定的文件不存在则会创建一个,SharedPreferences文件都是存放在/data/data/<package name‘>/shared_prefs/目录下的;第二个参数用于指定操作模式,目前只有MODE_PRIVATE这一种模式可选,它和直接传入0是等效的。

  2. Activity类中的getSharedPreferences()方法
    该方法只接收一个操作模式参数,因为使用这个方法时会自动将当前Activity的类名作为SharedPreferences的文件名。

    private fun put(){
        val editor = getSharedPreferences("data",Context.MODE_PRIVATE).edit()
        editor.putString("name","Brett")
        editor.putInt("age",23)
    }

从SharedPreferences中读取数据

    private fun get(){
        val prefs = getSharedPreferences("data",Context.MODE_PRIVATE)
        val name = prefs.getString("name","")
        val age = prefs.getInt("age",0)
        //......
    }

SQLite数据库存储

SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,通常只有几百kb的内存就足够了,因而特别适合在移动设备上使用。SQLite不仅支持标准的SQL语法,还遵循了数据库的ACID事务,所以只要以前有使用过其他的关系型数据库,就可以很快地上手SQLite。而SQLite比一般的数据库要简单得多,他甚至不需要设置用户名和密码就可以使用。
前面我们所学的文件存储和SharedPreferences存储只适用于保存一些简单的数据和键值对,当需要存储大量复杂的关系型数据的时候,就得要使用SQLite数据库存储。

创建数据库

Android为了让我们能够更加方便地管理数据库,专门提供了一个SQLiteOpenHelper帮助类,借助这个类可以非常简单地对数据库进行创建和升级。
SQLiteOpenHelper中有两个非常重要的实例方法:getReadableDatabase()和getWritableDatabase()。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则要创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。不同的是,当数据库不可写入的时候(如磁盘空间已满),getReadableDatabase()方法返回的对象以只读的方式打开数据库,而getWritableDatabase()方法则将抛出异常。构建出SQLiteOpenHelper的实例之后,再调用它的getReadableDatabase()或getWritableDatabase()方法就能创建数据库,数据库文件会存放在/data/data/<package name‘>/databases/目录下。此时,重写的onCreate方法也会得到执行,所以通常会在这里处理一些创建表的逻辑。

package com.example.myapplication

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

class MyDatabaseHelper(val context: Context,name:String,version:Int) : SQLiteOpenHelper(context,name,null,version) {//一般继承参数较少的那个构造方法

    private val createBook = "create table Book( " +
            "id integer primary key autoincrement," +
            "author text," + //text表示文本类型
            "price real," + //real表示浮点型
            "pages integer," +
            "name text)"

    private val createCategory = "create table Category( " +
            "id integer primary key autoincrement," +
            "category_name text," + //text表示文本类型
            "category_code integer)"

    override fun onCreate(db: SQLiteDatabase?) {//当Book表没有被创建的时候会回调onCreate方法,当Book表已被创建了,就不会回调该方法
        db?.execSQL(createBook)
        db?.execSQL(createCategory)
        Toast.makeText(context,"Create succeeded",Toast.LENGTH_SHORT).show()
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        if(oldVersion<=1){
            db?.execSQL(createCategory)
        }
    }
}
public class MyFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    public void setdata(){

    }

    MyDatabaseHelper helper = new MyDatabaseHelper(getActivity(),"test.db",1);

//第一个参数是表名,第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值null,一般我们不用这个功能,直接传入null即可,第三个参数是一个ContentValues对象,他提供了put方法用于向ContentValues中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。
    public long add(String name,int number){
        SQLiteDatabase db = helper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("author",name);
        values.put("pages",number);

        long id = db.insert("Book", null, values);
        db.close();
        return id;
    }

//第一个参数是表名,第二个参数是ContentValues对象,要把更新的数据在这里组装进去,第三,第四个参数用于约束更新某一行或某几行中的数据,不指定默认更新所有行
    public long update(int number){
        SQLiteDatabase db = helper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("pages",number);
        long id = db.update("Book", values,"pages=?",new String[]{String.valueOf(number)});
        db.close();
        return id;
    }

//第一个参数是表名,第二,第三个参数用于约束删除某一行或某几行的数据,不指定默认删除所有行
    public long delete(int number){
        SQLiteDatabase db = helper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("pages",number);
        long id = db.delete("Book", "pages=?",new String[]{String.valueOf(number)});
        db.close();
        return id;
    }

    public void query(int number){
        SQLiteDatabase db = helper.getReadableDatabase();
        ContentValues values = new ContentValues();
        values.put("pages",number);

        //参数1:表名;参数2:查询的列名;参数3:查询条件;参数4:查询参数值;参数5:分组条件;参数6:having条件;参数7:排序条件
        Cursor cursor = db.query("book", null, "pages=?", new String[]{String.valueOf(number)}, null, null, null);
        //是否有下一条值
        boolean result = cursor.moveToNext();
        while (result){
            long id = cursor.getLong(cursor.getColumnIndex("id"));
            String author = cursor.getString(1);
            long pages = cursor.getLong(2);
        }
        cursor.close();
        db.close();
    }

    //事务操作
    public void transaction(){
        SQLiteDatabase db = helper.getWritableDatabase();
        //开始数据库的事务
        db.beginTransaction();

        try{
            //数据库的增删改查操作
            db.execSQL();

            db.setTransactionSuccessful();//标记事务执行成功
        }catch (Exception e){
            Log.e("fail transaction",e.toString());
        }finally {
            db.endTransaction();
            db.close();
        }

    }
}

猜你喜欢

转载自blog.csdn.net/qq_36828822/article/details/113956508