美文网首页初见简友广场
Android基础(8)—数据持久化技术

Android基础(8)—数据持久化技术

作者: 危君子频道 | 来源:发表于2020-06-17 17:16 被阅读0次

    数据持久化技术

    一. SQLite数据库存储

    简介:

    SQLite,是一款轻量级的关系型数据库,是遵守ACID的关系型数据库管理系统,它的设计目标是嵌入式。由于它占用的资源非常少,所以在很多嵌入式设备都是用SQLite来存储数据。并且它目前支持Windows/Linux等等主流的操作系统,兼容性不错。Android作为目前主流的移动操作系统,完全符合SQLite占用资源少的优势,故在Android平台上,集成了一个嵌入式关系型数据库—SQLite。如果开发 Android 应用程序中,一定需要在 Android 上存储数据,使用SQLite 数据库是一种非常好的选择。

    SQLite可以看作为一个API库、数据库引擎库

    1.轻量级:使用 SQLite 只需要带一个动态库,就可以享受它的全部功能,而且那个动态库的尺寸相当小。

    2.独立性:SQLite 数据库的核心引擎不需要依赖第三方软件,也不需要所谓的“安装”。

    2.隔离性:SQLite 数据库中所有的信息(比如表、视图、触发器等)都包含在一个文件夹内,方便管理和维护。

    4.跨平台:SQLite 目前支持大部分操作系统,不只电脑操作系统,更在众多的手机系统也是能够运行,比如:Android和IOS。

    5.多语言接口:SQLite 数据库支持多语言编程接口。

    6.安全性:SQLite 数据库通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但只能有一个可以写入数据。

    小结优缺点:

    优点:轻量、高效;动态数据类型;绿色;单一文件;零配置

    缺点:并发性能低;SQL功能子集;网络文件

    支持的数据类型:

    一般数据采用的固定的静态数据类型,而SQLite采用的是动态数据类型,会根据存入值自动判断。SQLite具有以下五种数据类型:

    数据类型 解析
    NULL 空值
    INTEGER 带符号的整型,具体范围大小取决于存入数字的大小
    REAL 浮点数字,存储为8-byte IEEE浮点数
    TEXT 字符串文本
    BLOB 二进制对象

    基本的SQL语句:

    1.创建表

    primary key:主键

    autoincrement:自增型变量

    if not exists:如果创建的表已存在就不再创建

    "create table if not exists 表名 (id integer primary key autoincrement,列名1,列名2,列名3)"
    

    2.增(插入)

    "insert into 表名(列名1,列名2,列名3) values(?,?,?)",new Object[]{列名1的值,列名2的值,列名3的值}
    

    3.删

    "delete form 表名 where 列名 = ?",new String[]{删除条件}
    

    4.改(更新)

    "update 表名 set 修改的列名 = ? where 修改的列名 = ?",new String[]{修改后的值,修改的列名}
    

    5.查

    "select * from 表名 where 查询的列名 like ?", new String[]{条件}
    

    6.删除表

    drop table if exists 表名
    

    7.清空表

    delete from if exists 表名
    

    基本使用:

    1.获取SQLiteDataBase对象

    SQLiteDatabase database = this.openOrCreateDatabase("family", MODE_PRIVATE, null);
    

    2.创建数据表

    database.execSQL("create table family(id integer primary key autoincrement,name,age,relationship)");
    

    3.插入数据

    database.esecSQL("insert into family(name,age,relationship values(?,?,?),new Object[]{"Jimyoung",22,"son"})");
    database.esecSQL("insert into family(name,age,relationship values(?,?,?),new Object[]{"Papa",47,"father"})");
    database.esecSQL("insert into family(name,age,relationship values(?,?,?),new Object[]{"Mama",42,"mother"})");
    

    4.更新数据

    database.execSQL("update family set name = ? where name = ?",new String[]{"Boss","Papa"})
    

    5.查询数据

    一般通过cursor来得到查询数据并调用rawQuery来查询

    Cursor cursor = database.rawQuery("select * from family where name like ?",new String[]{"Jimyoung"});
    //实例化一个对象
    ArrayList<Map<String,Object list=new ArrayList<();
    //循环取值
    while(cursor.moveToNext()){
        //列按照从0开始算,1指的是name列
        String name = cursor.getString(1);
        //String name = cursor.getString(cursor.getColumnIndex("name"));或者可以这样写
        //实例化map对象                    
        Map<String,Object map = new HashMap<();                    
        //添加值                    
        map.put("name",name);                    
        //将map对象添加list中                    
        list.add(map);
    }
    
    

    6.删除数据

    database.execSQL("delete from family where name = ?",new String[]{"Jimyoung"});
    

    一般使用:

    一般情况下,会新建一个类继承SQLiteOpenHelper,在其封装增删改查四种方法。在onCreate方法中,写创建表;在onUpgrade方法中,它会根据版本号来更新表;在封装方法时,记得传SQLiteDatabase的对象,因为所有对表的操作都是通过它来的。

    public class MySQL extends SQLiteOpenHelper {        
      public MySQL(Context context, String name,SQLiteDatabase.CursorFactory factory, int version) { 
            super(context, name, factory, version);        
      }
            
      @Override        
      public void onCreate(SQLiteDatabase db) {            
           //创建表            
           db.execSQL("create table family (id integer primary key autoincrement, name, age, relationship)");
      }
    
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 
    {
        switch(newVersion){ 
          case 1: db.execSQL(第一个版本的建表语句); 
          case 2: db.execSQL(第二个版本的建表语句); 
          case 3: db.execSQL(第三个版本的建表语句); 
        }
    }
    

    使用时:

    //实例化封装的SQL类
    MySQL mySQL = new MySQL(this, "family.db", null, 1);
    //通过mySQL获取SQLiteDatabase对象
    SQLiteDatabase database = mySQL.getWritableDatabase();
    //之后通过mySQL调用封装方法
    

    二. SharedPreferences存储

    简介:

    SharedPreferences是Android平台上一个轻量级的存储类,使用键值对的方式来存储数据,用来保存应用的一些常用配置。比如Activity状态,Activity暂停时,将此activity的状态保存到SharedPereferences中;当Activity重载,系统回调方法onSaveInstanceState时,再从SharedPreferences中将值取出。

    SharedPreferences提供了java常规的Long、Int、String等类型数据的保存接口。

    SharedPreferences类似过去Windows系统上的ini配置文件,但是它分为多种权限,可以全局共享访问,最终是以xml方式来保存,整体效率来看不是特别的高,对于常规的轻量级而言比SQLite要好不少,如果真的存储量不大可以考虑自己定义文件格式。xml处理时Dalvik会通过自带底层的本地XML Parser解析,比如XMLpull方式,这样对于内存资源占用比较好.

    数据的四种操作模式:

    Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容。(只用这个就好,用 0 代替是一样的效果。)

    Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。(这个好像也废弃了)

    MODE_WORLD_READABLE:表示当前文件可以被其他应用读取。(在Android4.2废弃)

    MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。(在Android4.2废弃)

    SharedPreferences使用:

    将数据存储到SharedPreferences中:

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

    1.Context类中的getSharedPreferences()方法

    此方法接收两个参数,第一个参数用于指定SharedPreferences文件的名称,如果指定的文件不存在则会创建一个。SharedPreferences文件都是存放在/data/data/<package name/shared_prefs/目录下的。第二个参数用于指定操作模式。

    2.Activity类中的getPreferences()方法

    和上面那个方法类似,但只接收一个操作模式参数,因为使用这个方法时会自动将当前活动的类名作为SharedPreferences的文件名。

    3.PreferenceManager类中的getDefaultSharedPreferences()方法

    这是一个静态方法,它接收一个Context参数,并自动使用当前应用程序的包名作为前缀来命名SharedPreferences文件。

    得到SharedPreferences对象后,就可以开始向SharedPreferences文件中存储数据了。主要可以分为以下3步实现:

    (1)调用SharedPreferences对象的edit()方法来获取一个SharedPreferences.Editor对象。

    (2)向SharedPreferences.Editor对象中添加数据,比如添加一个布尔型数据就可以使用putBoolean()方法,添加一个字符串则使用putString()方法,以此类推。

    (3)调用apply()方法将添加的数据提交,从而完成数据存储操作。

    SharedPreferences.Editor editor=getSharedPreferences("data",MODE_PRIVATE).edit();
    editor.putString("name","Jimyoung");
    editor.putInt("age",22)
    editor.putBoolean("married",false);
    editor.apply();
    

    从SharedPreferences中读取数据:

    从SharedPreferences中读取数据很简单。SharedPreferences对象中提供了一系列的 get方法,用于对存储的数据进行读取,每种get方法都对应了SharedPreferences.Editor中的每一种put方法,比如读取一个布尔型数据就使用getBoolean()方法。这些get方法都接收两个参数,第一个参数时键,传入存储数据时使用的键就可以得到相应的值;第二个参数时默认值,即表示当传入的键找不到对应的值时会以什么样的默认值进行返回。

    SharedPrefenrences pref = getSharedPreferences("data",MODE_PRIVATE);
    String name=pref.getString("name","");
    int age=pref.getInt("age",0);
    boolean married=pref.getBoolean("married",false);
    Log.d("MainActivity","name is "+ name);
    Log.d("MainActivity","age is "+ age);
    Log.d("MainActivity","married is "+ married);
    
    //运行结果为:
    name is Jimyoung
    age is 22
    married is false
    

    补充:

    清除指定数据:

    SharedPreferences.Editor editor = userSettings.edit();
    editor.remove("KEY");
    editor.commit();
    

    清空数据:

    SharedPreferences.Editor editor = userSettings.edit();
    editor.clear();
    editor.commit();
    

    注意:

    如果在 Fragment 中使用SharedPreferences 时,需要放在onAttach(Activity activity)里面进行SharedPreferences 的初始化,否则会报空指针 即 getActivity()会可能返回null 。

    三. 文件存储

    介绍:

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

    API

    应用私有存储文件:/data/data/<package name/files/目录下。应用删除时,即清空该目录。

    //通过context对象获取私有目录:/data/data/packagename/files

    context.getFileDir().getPath();
    

    Context对象中文件操作的API及说明:

    方法名 说明
    openFileInput(String filename) 打开应用程序私有目录下的的指定私有文件以读入数据,返回一个FileInputStream 对象
    openFileOutput(String filename,操作模式) 打开应用程序私有目录下的的指定私有文件以写入数据,返回一个FileOutputStream 对象,如果文件不存在就创建这个文件。
    fileList() 搜索应用程序私有文件夹下的私有文件,返回所有文件名的String数组
    deleteFile(String fileName) 删除指定文件名的文件,成功返回true,失败返回false

    filename:不能包含路径分隔符“/”,如果文件不存在,Android会自动创建它。创建的文件保存在/data/data/<package name/files目录

    操作模式:

    常量 定义
    MODE_PRIVATE 默认模式,文件只可以被调用该方法的应用访问。当指定同样文件名的时候,所写入的内容将会覆盖原文件的内容。
    MODE_APPEND 如果文件已存在就向该文件的末尾继续写入数据,而不是覆盖原来的数据,不存在就创建新文件。

    将数据存储到文件中:

    private void saveContent() {
    
            String data = et_content.getText().toString();
            FileOutputStream out;
            BufferedWriter writer = null;
            View view = View.inflate(FileActivity.this, R.layout.layout_file, null);
            try {
                if (!TextUtils.isEmpty(et_content.getText())) {
                    out = openFileOutput("diary", Context.MODE_PRIVATE);
                    writer = new BufferedWriter(new OutputStreamWriter(out));
                    writer.write(data);
                } else {
                    Snackbar.make(view, "没有日记内容可以保存!", Snackbar.LENGTH_SHORT)
                            .setAction("知道了", new View.OnClickListener() {
                                @Override
                                public void onClick(View v) {
                                    Toast.makeText(FileActivity.this, "开始写日记吧", Toast.LENGTH_SHORT).show();
                                }
                            }).show();
                }
    
            } catch (IOException e) {
                Toast.makeText(FileActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
            } finally {
                try {
                    if (writer != null) {
                        writer.close();
                    }
                } catch (IOException e) {
                    Toast.makeText(FileActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
                }
            }
    
        }
    

    从文件中读取数据:

    private String loadContent() {
    
            FileInputStream in;
            BufferedReader reader = null;
            StringBuilder content = new StringBuilder();
            try {
                in = openFileInput("diary");
                reader = new BufferedReader(new InputStreamReader(in));
                String line;
                while ((line = reader.readLine()) != null) {
                    content.append(line);
                }
                if (!TextUtils.isEmpty(content)){
                    et_content.setText(content.toString());
                    et_content.setSelection(content.length());
                    Toast.makeText(this, "读取成功", Toast.LENGTH_SHORT).show();
                }else {
                    Toast.makeText(this, "没有日记内容", Toast.LENGTH_SHORT).show();
                }
            } catch (IOException e) {
                Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                }
            }
            return content.toString();
        }
    

    Demo:

    大家可以尝试写了一下demo,熟悉一下数据持久化操作。以下为demo截图:


    1.png 2.png 3.png

    上一篇:Android基础(7)—异步消息处理机制 Handler
    下一篇:Android基础(9)—多线程和异步任务

    精彩内容不够看?更多精彩内容,请到微信搜索 “危君子频道” 订阅号,每天更新,欢迎大家关注订阅!

    微信公众号

    相关文章

      网友评论

        本文标题:Android基础(8)—数据持久化技术

        本文链接:https://www.haomeiwen.com/subject/dmqytktx.html